@Ekopalypse said in RFC: Track previous position:
I just install it via pip install tree-sitter and pip install tree-sitter-languages and of course use PS3 with the preferred local installation to access it.
Much nicer. Modified script playground.py to work with that setup:
import os
import re
from tree_sitter_languages import get_parser
from Npp import editor, editor1, editor2, notepad, MENUCOMMAND, SCINTILLANOTIFICATION
class TreeSitterPlayground():
"""
Follow a `tree-sitter` parse output (in `editor2`) and highlight syntax
(in `editor1`).
"""
def __init__(self):
super().__init__()
self._edCallbacks = {
self._on_updateui: [
SCINTILLANOTIFICATION.UPDATEUI
]
}
self._cst = []
def _on_updateui(self, args):
if notepad.getCurrentView() != 1:
return
if self.DEBUG:
print(args)
if args['hwndFrom'] != editor2.hwnd:
return
line = editor2.getCurLine()
match = re.search(r'Node\stype\=(.*?)\,\sstart_point\=\((\d+)\,\s(\d+)\)\,\send_point\=\((\d+)\,\s(\d+)\)', line)
if (match is None) or (len(match.groups()) != 5):
return
# nm = match.group(1)
sl = int(match.group(2))
sc = int(match.group(3))
el = int(match.group(4))
ec = int(match.group(5))
if self.DEBUG:
print(f"[{sl}, {sc}] - [{el}, {ec}]")
editor1.gotoLine(sl)
spos = editor1.findColumn(sl, sc)
editor1.gotoLine(el)
epos = editor1.findColumn(el, ec)
editor1.setSelectionStart(spos)
editor1.setSelectionEnd(epos)
def _dump_tree(self, node, indent=0):
self._cst.append(f"{' '*indent}{node}")
if node.child_count > 0:
for c in node.children:
self._dump_tree(c, indent+1)
def parse(self):
"""Parse the current file."""
self._cst = []
# file name, path, extension parsing
full = notepad.getCurrentFilename()
path, file = os.path.split(full)
name, ext = os.path.splitext(file)
# get file language type and adjust for Tree-Sitter parser names
filetype = notepad.getLanguageName(notepad.getLangType()).lower()
if filetype == 'c++':
filetype = 'cpp'
elif filetype == 'shell':
filetype = 'bash'
# parse the file
try:
tree = get_parser(filetype).parse(editor.getText().encode())
except:
print(f"tree_sitter_languages `{filetype}' not found")
return
# recurse the CST, create the output string and put it in N++
self._dump_tree(tree.root_node)
cst = '\n'.join(self._cst)
notepad.new()
editor.setText(cst)
notepad.saveAs(f"{os.environ['TEMP']}/{name}.trs")
# Make sure the CST is in view 1 and the source file is in view 0
if notepad.getCurrentView() == 0:
notepad.menuCommand(MENUCOMMAND.VIEW_GOTO_ANOTHER_VIEW)
else:
notepad.open(full)
notepad.menuCommand(MENUCOMMAND.VIEW_GOTO_ANOTHER_VIEW)
notepad.open(f"{os.environ['TEMP']}/{name}.trs")
def start(self):
"""Start the service"""
for cb in self._edCallbacks:
editor.callback(cb, self._edCallbacks[cb])
self._ENABLED = True
def stop(self):
"""Stop the service"""
for cb in self._edCallbacks:
editor.clearCallbacks(cb)
self._ENABLED = False
if __name__ == '__main__':
try:
isinstance(tsp, TreeSitterPlayground)
print("Tree-Sitter Playground `tsp' already enabled")
except NameError:
tsp = TreeSitterPlayground()
tsp.start()
print("Tree-Sitter Playground instantiated as `tsp'")
tsp.parse()
Now, just open a file in Notepad++, run the âPlugins => Python Script => Scripts => playgroundâ and it will try to parse the current file and setup the output CST (syntax tree) in view 1 and the source file in view 0 to allow scrolling through the CST and auto-highlighting the source in view 0 as per my screenshot in the previous post.
Cheers.