-- Leo's gemini proxy

-- Connecting to jacksonchen666.com:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini;lang=en

Tridactyl with iTerm2

2023-11-08 22:21:11Z (last updated 2023-12-19 21:36:48Z)



NOTE: This post contains multiple licenses in use. The different license use is in the "script" section.


Heads up: This is a quick infodump near midnight. Expect severe incoherence.



Tridactyl is basically vim keys in Firefox. iTerm2 is a terminal emulator.


Tridactyl GitHub repo

iTerm2 homepage


Tridactyl supports a special feature: you can use your own editor in the terminal, something like vim.


I wanted to do something like that, but for some reason, I just couldn't figure it out. Until today.


Today, I have a script and lots more information to bring to you to the table. More specifically, how to setup Tridactyl with iTerm2.


Complications with iTerm2


iTerm2, from what I can tell, is a macOS application. It does not behave like on Linux, where you can run the program to start a terminal, then the program exits when the terminal exits.


This presented an interesting problem to solve: How do you make iTerm2 behave like a program which would open the terminal, and exits when the terminal is closed?


Well, the answer is I made a Python script using the Python API for iTerm2. That's a thing, and you have to enable it too.


Setting up Tridactyl


Steps:

1. Install

2. Setup native messaging

3. Setup editor command

4. ???

5. Profit


Installing Tridactyl


Easy. Go to the Firefox add-ons store and add to Firefox.


Firefox add-ons store


Setup native messaging


Setting up Tridactyl native messaging was easy:

1. Type `:installnative` in the browser

2. Paste the `curl | sh` command into your terminal

3. Let it do its thing

4. Type `:native` in the browser to check if it works


Of course, running with a Firefox based browser that is actually not Firefox

(it's LibreWolf) and uses a different path for native messaging and

everything.


So I had to replace step 3 with "Let it do its thing, then copy the files

over to the approprivate directory".


I ran something like this:

cp ~/Library/Application\ Support/Mozilla/NativeMessagingHosts/tridactyl.json ~/Library/Application\ Support/LibreWolf/NativeMessagingHosts/tridactyl.json

Setup editor


I had to set it to something like this:


:set editorcmd /opt/homebrew/bin/bash -c "'/Users/jackson/Library/Application Support/iTerm2/iterm2env/versions/3.10.4/bin/python3' '/Users/jackson/Library/Application Support/iTerm2/Scripts/neovim_in_new_window.py' %f %l %c"

Replace `/Users/jackson/Library/Application Support/iTerm2/iterm2env/versions/3.10.4/bin/python3` with whatever is correct by first checking `/Users/jackson/Library/Application Support/iTerm2/iterm2env/versions/` for folders, then finding the `python3` executable.


Because of some weirdness in macOS, you must use absolute paths for everything.

macOS $PATH weirdness issue


Debugging :editor


If running `:editor` gives you something like `TypeError: e2 is null`, it probably means you setup the `editorcmd` incorrectly.


Run the following in your browser's Tridactyl:

:set logging.native debug

Then check the console for the current webpage you're on, then run `:editor` again.


When finished debugging, run the following to revert debugging config:

:unset logging.native

About the script


I had to read a lot of the iTerm2 Python API documentation for this...


So, you cannot simply launch the iTerm2 binary and expect terminal windows to show up.


So I had to make a script that kinda emulates the terminal emulators on Linux, where you can run the program, a terminal shows up, then the program exits on terminal closing. That's what the script does basically.


It also takes character numbers and moves the cursor to the right place.


The Script {id=script}


NOTE: This code is licensed under the MIT license.


Heads up: This code is hardcoded to my configuration. Replace all absolute paths as necessary, and replace "LibreWolf" with "Firefox" if you use Firefox instead.


I put this file at `~/Library/Application Support/iTerm2/Scripts/neovim_in_new_window.py`. It also needs the Python API to be enabled in iTerm2


#!/usr/bin/env python3.10
# vim: tw=0

# tridactyl :editor but with iterm2 (which doesn't have the right behavior so
# this is basically a wrapper script for that)
# https://github.com/tridactyl/tridactyl/issues/4697
# https://github.com/tridactyl/tridactyl/issues/684

# MIT License
#
# Copyright (c) 2023 JacksonChen666
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import iterm2
import sys
import subprocess
# This script was created with the "basic" environment which does not support adding dependencies
# with pip.

async def main(connection):
    # Your code goes here. Here's a bit of example code that adds a tab to the current window:
    app = await iterm2.async_get_app(connection)
    #filename, line, character = "", 0, 0
    filename, line, character = sys.argv[1:4]

    #if len(sys.argv) >= 2:
    #    filename = sys.argv[1]

    #if len(sys.argv) >= 3:
    #    line = sys.argv[2]

    #if len(sys.argv) >= 4:
    #    character = sys.argv[3]

    # defaults already assigned earlier
    command = f"/opt/homebrew/bin/bash -l -i -c \"/opt/homebrew/bin/nvim {filename} '+normal!{line}Gzv{character}|'\""
    print("#", command)

    new_window = await iterm2.Window.async_create(connection, command=command)
    print("#", new_window)

    await app.async_activate(raise_all_windows=False, ignoring_other_apps=True)
    await new_window.async_activate()

    #print(new_window.current_tab)
    async with iterm2.FocusMonitor(connection) as monitor:
        while True:
            # TODO: make it trigger if it's the last window and it closes
            await monitor.async_get_next_update()
            if new_window not in app.windows:
                break
    print("# end")
    # focus web browser
    subprocess.run(['osascript', '-e' 'tell application "LibreWolf" to activate'])

iterm2.run_until_complete(main)

Does it work?


Yes!


public inbox (comments and discussions)

public inbox archives

(mailing list etiquette for public inbox)

-- Response ended

-- Page fetched on Fri May 10 06:49:21 2024