Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flexible grammar installer #54

Open
wants to merge 57 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
567438c
added functionality to add grammars
Oct 26, 2023
2038954
use local queries
Oct 26, 2023
765f350
added queries path
Oct 26, 2023
9251830
mkdir queries path
Oct 26, 2023
a335aeb
removed
Oct 26, 2023
5c7499a
minor formatting
Oct 26, 2023
793e30b
removed
Oct 26, 2023
3f4d231
added end
Oct 26, 2023
3a9e679
fixed typo
Oct 26, 2023
7aa5302
removed installer dependency
Oct 26, 2023
a2a3f83
fixed add grammars
Oct 26, 2023
8d620b9
simplified configuration to one single function
Oct 26, 2023
a6ac76b
updated doc
Oct 26, 2023
664a69b
added missing require
Oct 26, 2023
c9366e4
adding language to map only after installing
Oct 26, 2023
bbe676e
refactor!: refactored code and used camel case for all functions
Oct 27, 2023
fad305f
style: reformatted using lua lsp
Oct 27, 2023
300df49
refactor!: refactoring of installation and configuration of grammars …
Oct 27, 2023
0ef96db
refactor: moved localPath from `highlights` to `util`
Oct 27, 2023
ca43b2a
feat: added defaults, installFromUrl and defaults queries support
Oct 27, 2023
b9ab1e3
refactor: moved installation functions to `installer`
Oct 27, 2023
66b7d09
style: formatted using lua lsp
Oct 27, 2023
3b2ed63
refactor: added localPath to util module
Oct 27, 2023
ddb480f
feat: added back default queries
Oct 27, 2023
960a5c0
fix: installation of default queries now works fine
Oct 27, 2023
b6b4502
docs: updated README with default languages and new module structure
Oct 27, 2023
7264bea
feat: added command status to check health of grammars
Oct 27, 2023
0bc6e9b
refactor: moved `exists` and `isDir` to util
Oct 27, 2023
f4d6970
feat: added table of installed grammars
Oct 27, 2023
a7d2756
Revert "minor formatting"
Oct 29, 2023
5076eee
fix: inconsistency in the readme solved
Oct 29, 2023
15bdef3
style: using single quotes everywhere
Oct 29, 2023
698fdd0
feat: added default git repos and the possibility to chose between pr…
Oct 29, 2023
a4d566b
doc: updated with latest changes
Oct 29, 2023
3099dd9
refactor: extracted method `installGrammar` from `addGrammar`.
Oct 29, 2023
34b0776
feat: added simple update-all command
Oct 29, 2023
2446f29
feat: added command to update a specific language grammar
Oct 29, 2023
4026229
refactor: extracted method `exec` and `rmDir` from installer to util
Oct 29, 2023
e125b80
feat: added command clean to remove unused parsers and queries
Oct 29, 2023
5b29cbf
fix: clean uses the table `languages.grammars` to enstablish used gra…
Oct 29, 2023
11f351f
Update README.md
Mandarancio Jan 25, 2024
4037982
Update README.md
Mandarancio Jan 25, 2024
eb36b1e
fix: quiet log for installer
Jan 25, 2024
a7295ca
fix: removed `d` as it is no longer precompiled
Jan 25, 2024
774a081
feat: using tables for filenames and extensions
Jan 25, 2024
5b0fd55
feat: update documentation with new extensions/filenames configuration
Jan 25, 2024
b3bdffe
fix: fixed iteration in table
Jan 25, 2024
7acffda
fix: `evergreen:status` work with extensions and filenames table
Jan 25, 2024
199a327
fix: removed `D` lang from default grammars
Jan 25, 2024
a086f92
fix: using system utilities to remove directories
Jan 26, 2024
9054fe5
feat: simplify readme
Feb 7, 2024
230c829
feat: added function to replace `~` with home path
Feb 12, 2024
2e74455
fix: installGrammarFromPath and installQueries improved and fixed
Feb 12, 2024
bc19546
doc: updated to fix error in example
Feb 12, 2024
041d2c7
feat: using file patterns with regex instead of extensions and filenames
Feb 16, 2024
af1f741
merged
Aug 5, 2024
d68ab5c
Merge branch 'Evergreen-lxl-master'
Aug 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 92 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,98 @@ It is work in progress, but functions well.
| ![](before.png) | ![](after.png) |

# Supported Languages
- [x] [C][tree-sitter-c]
- [x] [C++][tree-sitter-cpp]
- [ ] CSS
- [x] [D][tree-sitter-d]
- [x] [Diff][tree-sitter-diff]
- [x] [Go][tree-sitter-go]
- [x] [go.mod][tree-sitter-go-mod]
- [ ] HTML
- [x] [Javascript/JSX][tree-sitter-javascript]
- [x] [Julia][tree-sitter-julia]
- [x] [Lua][tree-sitter-lua]
- [x] [Rust][tree-sitter-rust]
- [x] [Zig][tree-sitter-zig]

If you want more languages supported, open an issue.

Any language supported by `tree-sitter` should (in theory) be supported as well.

It is possible to use grammar installed locally or directly from their git repository. Additionally
it is possible to specify where to find the queries of the language as well as use sub path for projects
containing more then one language.
## Default grammars

A few grammars have default configurations, pre-compiled parsers and custom queries:

The supported languages are:

Mandarancio marked this conversation as resolved.
Show resolved Hide resolved
- [C][tree-sitter-c]
- [C++][tree-sitter-cpp]
- [D][tree-sitter-d]
- [Diff][tree-sitter-diff]
- [Go][tree-sitter-go]
- [go.mod][tree-sitter-go-mod]
- [Javascript/JSX][tree-sitter-javascript]
- [Julia][tree-sitter-julia]
- [Lua][tree-sitter-lua]
- [Rust][tree-sitter-rust]
- [Zig][tree-sitter-zig]

To use any of this grammars simply add this to your conifg

```lua
local egconfig = require "plugins.evergreen.config"

egconfig.addGrammar {
lang = "LANGUAGE",
precompiled = true -- optional: default true, if false use default git repository to install grammar
}
```
Mandarancio marked this conversation as resolved.
Show resolved Hide resolved


## Locally installed grammars

To add a grammar to lite-xl simply add the following configuration to your `init.lua` script:

```lua
local egconfig = require "plugins.evergreen.config"

egconfig.addGrammar {
path = "YOUR GRAMMAR LOCAL PATH",
lang = "LANGUAGE NAME",
extensions = "FILE EXTENSIONS", -- optional for extension name based
filename = "FILE NAME", -- optional for file name based
queries = "QUERIES SUB PATH", -- optional sub path of grammar queries, default = 'queries'
}
```

## From git repository
To add a grammar directly from a git repository add this to your `init.lua` scripts:

```lua
local egconfig = require "plugins.evergreen.config"
egconfig.addGrammar {
git = "GIT REPO",
lang = "LANGUAGE NAME",
extensions = "FILE EXTENSIONS", -- optional for extension name based
filename = "FILE NAME", -- optional for file name based
queries = "QUERIES SUB PATH", -- optional sub path of grammar queries, default = 'queries'
subpath = "GRAMMAR SUB PATH", -- optional sub path if grammar is nested, default = nil
revision = "SPECIFIC GIT REVISION", -- optional version of the code to clone
}
```

## Example

```lua
local egconfig = require "plugins.evergreen.config"

egconfig.addGrammar {
path = "~/.grammars/tree-sitter-epics/epics-db",
lang = "epics_db",
extensions = "db,vdb",
}

egconfig.addGrammar {
git = "https://github.com/tree-sitter/tree-sitter-cpp.git",
lang = "cpp",
extensions = "cpp,hpp,cc",
}

egconfig.addGrammar {
git = "https://github.com/tree-sitter/tree-sitter-c.git",
lang = "c",
extensions = "c,h",
}

Mandarancio marked this conversation as resolved.
Show resolved Hide resolved
```

# Requirements
- Lite XL 2.1+ or [Pragtical](https://github.com/pragtical/pragtical)
Expand Down
14 changes: 11 additions & 3 deletions config.lua
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
local util = require 'plugins.evergreen.util'
local installer = require 'plugins.evergreen.installer'

local home = HOME or os.getenv 'HOME'

local M = {
dataDir = PLATFORM ~= 'Windows'
and ('~/.local/share/evergreen'):gsub('~', home)
or string.format('%s\\evergreen', os.getenv 'APPDATA')
and ('~/.local/share/evergreen'):gsub('~', home)
or string.format('%s\\evergreen', os.getenv 'APPDATA')
}

M.parserLocation = util.join {M.dataDir, 'parsers'}
M.parserLocation = util.join { M.dataDir, 'parsers' }
M.queryLocation = util.join { M.dataDir, 'queries' }

-- add grammar
function M.addGrammar(options)
installer.addGrammar(options, M)
end

return M
13 changes: 5 additions & 8 deletions highlights.lua
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
local parser = require 'plugins.evergreen.parser'
local languages = require 'plugins.evergreen.languages'
local config = require 'plugins.evergreen.config'

local M = {}

local function localPath()
local str = debug.getinfo(2, 'S').source:sub(2)
return str:match '(.*[/\\])'
end

function M.query(ftype)
local ff = io.open(string.format('%s/queries/%s/highlights.scm', localPath(), ftype))
local ff = io.open(string.format('%s/%s/highlights.scm', config.queryLocation, ftype))
if not ff then
return ""
end
Expand All @@ -23,8 +20,8 @@ end
--- @param doc core.doc
function M.init(doc)
local function getSource(n)
local startPt = n:start_point()
local endPt = n:end_point()
local startPt = n:start_point()
local endPt = n:end_point()
local startRow, startCol = startPt.row + 1, startPt.column + 1
local endRow, endCol = endPt.row + 1, endPt.column

Expand Down Expand Up @@ -53,7 +50,7 @@ function M.init(doc)
query = p:query(M.query(languages.fromDoc(doc))):with {
['any-of?'] = function(t, ...)
local src = getSource(t)
for _, match in ipairs {...} do
for _, match in ipairs { ... } do
if src == match then return true end
end
return false
Expand Down
117 changes: 106 additions & 11 deletions init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ local core = require 'core'
local config = require 'plugins.evergreen.config'
local util = require 'plugins.evergreen.util'
local home = HOME or os.getenv 'HOME'
local languages = require 'plugins.evergreen.languages'
local installer = require 'plugins.evergreen.installer'

local function appendPaths(paths)
for _, path in ipairs(paths) do
package.cpath = package.cpath .. ';' .. path:gsub('~', home)
Expand All @@ -11,11 +14,12 @@ end

system.mkdir(config.dataDir)
system.mkdir(config.parserLocation)
system.mkdir(config.queryLocation)

appendPaths {
util.join {config.dataDir, '?' .. util.soname},
util.join {config.parserLocation, '?', 'libtree-sitter-?' .. util.soname},
util.join {config.parserLocation, '?', 'parser' .. util.soname},
util.join { config.dataDir, '?' .. util.soname },
util.join { config.parserLocation, '?', 'libtree-sitter-?' .. util.soname },
util.join { config.parserLocation, '?', 'parser' .. util.soname },
}

if PLATFORM ~= 'Windows' then
Expand Down Expand Up @@ -44,13 +48,17 @@ core.log('%s', ok)
if not ok then
core.add_thread(function()
core.log 'Could not require ltreesitter, attempting to install...'
local url = string.format('https://github.com/TorchedSammy/evergreen-builds/releases/download/ltreesitter/ltreesitter%s', util.soname)
local url = string.format(
'https://github.com/TorchedSammy/evergreen-builds/releases/download/ltreesitter/ltreesitter%s', util.soname)

local out, exitCode
if PLATFORM == 'Windows' then
out, exitCode = exec({'powershell', '-Command', string.format('Invoke-WebRequest -OutFile ( New-Item -Path "%s" -Force ) -Uri %s', util.join {config.dataDir, 'ltreesitter' .. util.soname}, url)})
out, exitCode = exec({ 'powershell', '-Command',
string.format('Invoke-WebRequest -OutFile ( New-Item -Path "%s" -Force ) -Uri %s',
util.join { config.dataDir, 'ltreesitter' .. util.soname }, url) })
else
out, exitCode = exec({'curl', '-L', '--create-dirs', '--output-dir', config.dataDir, '--fail', url, '-o', 'ltreesitter' .. util.soname})
out, exitCode = exec({ 'curl', '-L', '--create-dirs', '--output-dir', config.dataDir, '--fail', url, '-o',
'ltreesitter' .. util.soname })
end
if exitCode ~= 0 then
core.error('An error occured while attempting to download ltreesitter\n%s', out)
Expand All @@ -71,7 +79,6 @@ local Highlight = require 'core.doc.highlighter'
local parser = require 'plugins.evergreen.parser'
local highlights = require 'plugins.evergreen.highlights'
require 'plugins.evergreen.style'
require 'plugins.evergreen.installer'

--- @class core.doc
--- @field treesit boolean
Expand All @@ -86,7 +93,7 @@ end
local function accumulateLen(tbl, s, e)
local len = 0

for i=s,e do
for i = s, e do
len = len + tbl[i]:len()
end

Expand Down Expand Up @@ -184,7 +191,7 @@ end
local oldTokenize = Highlight.tokenize_line
function Highlight:tokenize_line(idx, state)
if not self.doc.treesit then return oldTokenize(self, idx, state) end

local txt = self.doc.lines[idx]
local row = idx - 1
local toks = {}
Expand All @@ -207,7 +214,7 @@ function Highlight:tokenize_line(idx, state)
local startPos = startPt.row < row and 1 or startPt.column + 1
local endPos = endPt.row > row and #txt or endPt.column

local i = #buf - 1
local i = #buf - 1
while i >= 1 and buf[i + 1] < startPos do
local e = buf[i + 1]
toks[#toks + 1] = buf[i]
Expand Down Expand Up @@ -237,7 +244,7 @@ function Highlight:tokenize_line(idx, state)

i = i - 2
end

return {
init_state = state,
state = state,
Expand All @@ -255,3 +262,91 @@ command.add('core.docview!', {
end
end
})

command.add(nil, {
['evergreen:status'] = function()
local notInstalled = {}
local installed = {}
local errorCounter = 0
for lang, options in pairs(languages.grammars) do
local lib = util.join { config.parserLocation, lang, 'parser.so' }
local queries = util.join { config.queryLocation, lang, 'highlights.scm' }
if not util.exists(lib) or not util.exists(queries) then
errorCounter = errorCounter + 1
table.insert(notInstalled, lang)
else
local str = ' - ' .. lang .. ': '
if options.extensions ~= nil then
str = str .. options.extensions .. ' '
end
if options.filename ~= nil then
str = str .. options.filename .. ' '
end
if options.filename == nil and options.extensions == nil then
str = str .. lang
end
table.insert(installed, str)
end
end
core.log('[Evergreen] Installed grammars:\n%s', table.concat(installed, '\n'))
if errorCounter > 0 then
core.warn('[Evergreen] grammars not operational:\n%s', table.concat(notInstalled, '\n'))
end
end
})


local exts = {}

for k, _ in pairs(languages.grammars) do
table.insert(exts, k)
end


command.add(nil, {
['evergreen:update-all'] = function()
for lang, options in pairs(languages.grammars) do
core.log('[Evergreen] updating grammar for language "%s"', lang)
installer.installGrammar(options, config)
end
end
})

command.add(nil, {
['evergreen:update'] = function()
core.command_view:enter('Update Treesitter parser for', {
submit = function(lang)
if not languages.grammars[lang] then
core.error('Unknown parser for language ' .. lang)
return
end
core.log('Installing parser for ' .. lang)
installer.installGrammar(languages.grammars[lang], config)
end,
suggest = function()
return exts
end
})
end
})

command.add(nil, {
['evergreen:clean'] = function()
core.add_thread(function()
for _, parser_dir in pairs(system.list_dir(config.parserLocation)) do
local path = util.join { config.parserLocation, parser_dir }
if util.isDir(path) and languages.grammars[parser_dir] == nil then
core.log('[Evergreen] removing unused parser "%s"', parser_dir)
util.rmDir(path)
end
end
for _, query_dir in pairs(system.list_dir(config.queryLocation)) do
local path = util.join { config.queryLocation, query_dir }
if util.isDir(path) and languages.grammars[query_dir] == nil then
core.log('[Evergreen] removing unused queries "%s"', query_dir)
util.rmDir(path)
end
end
end)
end
})
Loading