💾 Archived View for jacksonchen666.com › posts › 2023-11-08 › 22-21-11 › index.gmi captured on 2024-02-05 at 09:37:09. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-12-28)
-=-=-=-=-=-=-
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 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.
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.
Steps:
1. Install
2. Setup native messaging
3. Setup editor command
4. ???
5. Profit
Easy. Go to the Firefox add-ons store and add to Firefox.
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
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.
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
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.
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)
Yes!