Editor JS snippets [support thread]

New add-on, a derivation/improvement of Custom editor keymap - AnkiWeb, main differences:

  • In addition to being available from keyboard shortcuts the JS snippets and symbols are available from the context menu in the editor (in main context menu or as submenus, configurable).
  • Also available as separate shortcut-invokeable menus ("Ctrl+J" and "Ctrl+S" per default, configurable) allowing selection from the menus from keyboard only.
  • JS snippets have a Pre and Post JS string to allow for passing variables etc. to JS script stored in file. File is interpreted as filename and contents are loaded.
  • File names are interpreted as being located in the add-on folder/user_files (to avoid them being deleted on add-on update).
  • To store JS snippet in file config only just write it in the pre or post string.
  • Shortcuts in config specified in Qt format (see https://doc.qt.io/qt-5/qkeysequence.html)
  • It is implemented "python-side" rather than "javascript-side" although what is inserted is JavaScript
  • Just as in Custom editor keymap symbols (strings really) can be inserted as plain text or HTML.
  • Feel free to share your JS snippets in https://forums.ankiweb.net/t/useful-javascript-snippets-for-the-editor/14536

1


Outstanding

  • Figure out how to get X/Y position of caret to allow keyboard popping of menues at caret rather than mouse cursor (which may be located anywhere on the screen).

Any chance you could post the source code somewhere?

EDIT: never mind, that can obviously be found in the addon folder, my bad :slight_smile:

It might however still be nice to host to github or another git hosting service that way people could contribute, I’m not certain whether my changes are still helpful since I changed quite a lot and had no need for symbols but with the changes I made to your code snippets are now reloaded live, i.e. if you change a file in your user_files those changes are reflected immediately in the editor. I wasn’t able to get this to work for the config file itself, although I’m not certain it’s even possible. What is missing in my code and I do believe in yours is the ability to undo changes. Have you got any idea how to do that?

In any case here are my changes, take the code from them as you like or if you open a git repository I could see if I can open a pull request:
init.py

import os
import sys
from collections import namedtuple
from functools import partial

from anki.hooks import addHook
from aqt import gui_hooks, mw, utils
from aqt.qt import QCursor, QKeySequence, QMenu

JS_SECTION = "JS snippets"
JS_MENU_SCUT = None

# Build the JS commands from pre/post and file contents
def build_js(snippet) -> str:
    file = ""
    pre = snippet.pre
    post = snippet.post
    fname = snippet.fname
    file = ""
    if fname:
        for f in fname.split(";"):
            path = os.path.join(os.path.dirname(__file__), f"user_files/{f}")
            with open(path) as fh:
                file += fh.read().strip()
    # return pre + file + post
    return ";".join([pre, file, post])


# Add shortcuts to editor
def setup_cuts(snippets, scs, edit):
    def fn(s):
        edit.web.eval(build_js(s))
        return

    scs += [(s.cut, partial(fn, s), True) for s in snippets]

    menu = QMenu("Custom", edit.web)
    map(lambda s: menu.addAction(s.name, partial(fn, s), s.cut), snippets)
    menu.popup(QCursor.pos())

    # DEBUG:
    # for i in scs:
    #     if isinstance(i[0], QKeySequence):
    #         func = inspect.getsourcelines(i[1])[0]
    #         print(f"INFO:{func}")
    #     print(i)
    #     print("\n")


# Only set up if not already loaded
if not 2065559429 in sys.modules:
    config = mw.addonManager.getConfig(__name__)

    # Setup base shortcuts
    JS_MENU_SCUT = config["Snippet menu shortcut"]

    config_snippets = config["Snippets"]
    Snippet = namedtuple("Snippet", ["name", "cut", "fname", "pre", "post"])

    def get_snippets():
        return [
            Snippet(sc["Name"], sc["Shortcut"], sc["File"], sc["Pre"], sc["Post"])
            for sc in mw.addonManager.getConfig(__name__)["Snippets"]
        ]

    # addHook(
    #     "EditorWebView.contextMenuEvent", mouse_context
    # )  # Legacy hook but it does fire
    # gui_hooks.editor_will_show_context_menu.append(on_pop_context) # New style hooks doesn't fire until Image Occlusion Enhanced is fixed
    gui_hooks.editor_did_init_shortcuts.append(partial(setup_cuts, get_snippets()))

Config File

{
  "name": "js_snippets",
  "config": {
    "Snippet context submenu": "false",
    "Snippet menu shortcut": "Ctrl+J",
    "Snippets": [
      {
        "File": "test.js",
        "Name": "Test",
        "Post": "",
        "Pre": "",
        "Shortcut": "Alt+T"
      },
      {
        "File": "util.js;bracket.js",
        "Name": "Bracket",
        "Post": "",
        "Pre": "",
        "Shortcut": "Alt+B"
      },
      {
        "File": "util.js;jaxc.js",
        "Name": "Jaxc",
        "Post": "",
        "Pre": "",
        "Shortcut": "Alt+J"
      },
      {
        "File": "util.js;ht.js",
        "Name": "Highlight Text",
        "Post": "",
        "Pre": "",
        "Shortcut": "Alt+H,T"
      },
      {
        "File": "util.js;hm.js",
        "Name": "Highlight Math",
        "Post": "",
        "Pre": "",
        "Shortcut": "Alt+H,M"
      },
      {
        "File": "util.js;math.js",
        "Name": "Math",
        "Post": "",
        "Pre": "",
        "Shortcut": "Alt+M"
      },
      {
        "File": "color.js",
        "Name": "Color Green",
        "Post": "setColor('green')",
        "Pre": "",
        "Shortcut": "Ctrl+G,G"
      },
      {
        "File": "color.js",
        "Name": "Color Black",
        "Post": "setColor('black')",
        "Pre": "",
        "Shortcut": "Ctrl+G,B"
      }
    ],
    "Symbol context submenu": "true",
    "Symbol menu shortcut": "Ctrl+S",
    "Symbols": [
      { "HTML": "false", "Shortcut": "Alt+Left", "Symbol": "\u2190" },
      { "HTML": "false", "Shortcut": "Alt+Right", "Symbol": "\u2192" },
      { "HTML": "false", "Shortcut": "Alt+Up", "Symbol": "\u2191" },
      { "HTML": "false", "Shortcut": "Alt+Down", "Symbol": "\u2193" }
    ]
  }
}

I will look into putting it up on GitHub.

Let me know if you need any help in doing that, it’s not that hard but can be a bit tricky if you haven’t done so before.

Source uploaded to GitHub: GitHub - TRIAEIOU/Editor-Scripts-Symbols: Anki addon to run custom scripts and insert symbols/strings in the Anki editor using keyboard shortcuts or popup menus.

Please could you update the addon “Uppercase Lowercase” which exist for anki 2.0 for anki 2.1 ?

Sorry, that’s not my addon.