Skip to content

Syntax highlighting that plays well with font-lock #36

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

Merged
merged 43 commits into from
May 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4ee6eec
Spell out the purpose of tree-sitter-langs more clearly
ubolonton Apr 8, 2020
c0e0477
Start tree-sitter-hl.el
ubolonton Apr 7, 2020
4ff76fe
Make core highlighting logic more or less working
ubolonton Apr 8, 2020
ab964d4
Support assigning multiple faces to a node
ubolonton Apr 8, 2020
710d2be
Make tree-sitter-hl--highlight-region return a jit-lock-bounds
ubolonton Apr 8, 2020
d89a37e
Add notes about org-mode/markdown pattern of short-lived buffers
ubolonton Apr 9, 2020
b1823c4
Somewhat better faces
ubolonton Apr 9, 2020
fea3e96
Define global-tree-sitter-mode
ubolonton Apr 9, 2020
c678029
Move the initial parse after tree-sitter-mode-hook
ubolonton Apr 9, 2020
8a66f5c
Add tree-sitter-after-first-parse-hook
ubolonton Apr 10, 2020
688de32
Add new minor mode for syntax highlighting: tree-sitter-hl-mode
ubolonton Apr 11, 2020
ff6857a
Extract convenient macro tree-sitter--handle-dependent-mode
ubolonton Apr 13, 2020
5cbe1fb
Make tree-sitter-debug into a dependent minor mode
ubolonton Apr 13, 2020
51efa7f
Add tree-sitter-function-call-face
ubolonton Apr 15, 2020
28f4271
Fix ts-make-query not working when quoted patterns contain predicates
ubolonton Apr 14, 2020
6874deb
Add mechanism for modes and end users to specify highlighting patterns
ubolonton Apr 15, 2020
55cf498
Run `cask build` in build scripts, in addition to `cargo build`
ubolonton Apr 19, 2020
968e912
Ignore temp files created during byte compilation
ubolonton Apr 19, 2020
97ea954
Move lookup of default highlighting patterns to tree-sitter-langs
ubolonton Apr 16, 2020
a490c13
Fix a byte-compilation warning
ubolonton Apr 16, 2020
3a2cbd1
Remove tree-sitter-hl-default-faces
ubolonton Apr 16, 2020
302ea43
Update emacs crate to 0.14.0
ubolonton Apr 18, 2020
5a66b0e
Fix incorrect parsing after a `upcase-initials-region' call
ubolonton Apr 18, 2020
916f071
Fix incorrect parsing after deleting non-ascii text
ubolonton Apr 19, 2020
5a9a841
Prioritize patterns that appear earlier in the highlighting query
ubolonton Apr 19, 2020
ab812c5
Don't track empty tree-sitter--text-before-change
ubolonton Apr 21, 2020
6ffdc1a
Rename tree-sitter-query to tree-sitter-debug-query to avoid confusion
ubolonton Apr 15, 2020
f486b6a
Fix tests on Travis
ubolonton Apr 22, 2020
c566c1f
Read test files using utf-8 coding, so that tests work on Windows
ubolonton Apr 23, 2020
2bf0905
Extend the region to be highlighted a bit before running the query
ubolonton Apr 23, 2020
8291113
Add tree-sitter-hl vs. font-lock benchmark test
ubolonton Apr 17, 2020
786816a
Remove useless progress bars when compiling language grammars
ubolonton Apr 26, 2020
12c0bb5
Make CI jobs build in release mode
ubolonton Apr 26, 2020
d75528a
Store capture tags in query to avoid unnecessary string creation
ubolonton Apr 25, 2020
3fc1751
Optimize ts-node-position-range; add function ts-node-byte-range
ubolonton Apr 25, 2020
f7ddb98
Optimize querying by not creating temporary node objects in Lisp
ubolonton Apr 26, 2020
083fed3
Rename ts-buffer-input into ts--buffer-input
ubolonton Apr 26, 2020
5eed1cf
Optimize querying by returning byte ranges, instead of captured nodes
ubolonton Apr 30, 2020
a0f90a0
Update Rust grammar to fix flickering syntax highlighting when typing
ubolonton Apr 30, 2020
7525d49
Optimize querying by returning pre-sorted captures instead of matches
ubolonton Apr 30, 2020
1c56c74
Add customization option tree-sitter-hl-face-mapping-function
ubolonton May 1, 2020
e0acb1c
Explain why respecting font-lock-add-keywords is difficult
ubolonton May 1, 2020
671694b
Rename query-cursor range-restriction functions, to improve clarity
ubolonton May 1, 2020
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
5 changes: 4 additions & 1 deletion .azure-pipelines/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ resources:
steps:
- template: .azure-pipelines/steps/setup-rust.yml@emacs-module-rs
- template: .azure-pipelines/steps/setup-llvm.yml@emacs-module-rs
- template: steps/-build.yml
- template: .azure-pipelines/steps/setup-emacs.yml@emacs-module-rs
- template: .azure-pipelines/steps/setup-cask.yml@emacs-module-rs
- template: steps/-build.yml
parameters:
target: release
- template: steps/setup-tree-sitter-cli.yml
- template: steps/-test.yml
3 changes: 2 additions & 1 deletion .azure-pipelines/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ jobs:
steps:
- template: .azure-pipelines/steps/setup-rust.yml@emacs-module-rs
- template: .azure-pipelines/steps/setup-llvm.yml@emacs-module-rs
- template: .azure-pipelines/steps/setup-emacs.yml@emacs-module-rs
- template: .azure-pipelines/steps/setup-cask.yml@emacs-module-rs
- template: steps/-build.yml
parameters:
target: release
- template: .azure-pipelines/steps/setup-emacs.yml@emacs-module-rs
- template: steps/setup-tree-sitter-cli.yml
- template: steps/-test.yml
- template: steps/-save-binaries.yml
Expand Down
2 changes: 2 additions & 0 deletions .azure-pipelines/steps/-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ parameters:

steps:
- powershell: |
cask install
.\bin\build.ps1 ${{ parameters.target }}
displayName: Build all packages (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))

- bash: |
cask install
./bin/build ${{ parameters.target }}
displayName: Build all packages
condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/target
**/*.rs.bk
**/*.elc
**/*.elc*
**/.cask
grammars/
lisp/tree-sitter-dyn.*
Expand Down
5 changes: 4 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,12 @@ before_install:
- git clone -b master https://github.com/ubolonton/evm.git $HOME/.evm
- evm config path /tmp
- evm install $EVM_EMACS --use --skip
- curl -fsSL https://raw.githubusercontent.com/cask/cask/master/go | python
- export PATH="$HOME/.cask/bin:$PATH"

install:
- make build
- cask install
- ./bin/build

before_script:
- nvm install 10
Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ name = "tree_sitter_dyn"
crate-type = ["cdylib"]

[dependencies]
emacs = "0.13.0"
emacs = "0.14.0"
libloading = "0.5.1"
tree-sitter = "0.6.3"

Expand Down
5 changes: 5 additions & 0 deletions Cask
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@
"Cargo.toml"
"Cargo.lock"
"src")

(source melpa)

(development
(depends-on "rust-mode"))
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ If you want to hack on `emacs-tree-sitter` itself, see the section [Setup for De
- Show the debug view of a buffer's parse tree
```emacs-lisp
(require 'tree-sitter-debug)
(tree-sitter-debug-enable)
(tree-sitter-debug-mode)
```
- Get names of all functions in a Rust file:
```emacs-lisp
(with-current-buffer "types.rs"
(seq-map (lambda (capture)
(pcase-let ((`(_ . ,node) capture))
(ts-node-text node)))
(tree-sitter-query [(function_item (identifier) @name)])))
(tree-sitter-debug-query [(function_item (identifier) @name)])))
```
- Write a simple extension to `expand-region`:
```emacs-lisp
Expand Down Expand Up @@ -125,12 +125,13 @@ For consistency with Emacs's conventions, this binding has some differences comp
+ `ts-make-query`: create a new query.
+ `ts-make-query-cursor`: create a new query cursor.
+ `ts-query-matches`, `ts-query-captures`: execute a query, returning matches/captures.
+ `ts-set-byte-range`, `ts-set-point-range`: limit query execution to a range.

## Setup for Development

Clone this repo and add its `lisp` and `langs` directories to `load-path`.

Install [cask](https://cask.readthedocs.io) and run `cask install` to install dev dependencies.

If you want to hack on the high-level features (in Lisp) only:
- Evaluate this (once) to download the necessary binaries:
```emacs-lisp
Expand Down
2 changes: 2 additions & 0 deletions bin/build
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ source "$here/env.bash"

MODULE_DIR="$PROJECT_ROOT/target/$TARGET"
cp -f "$MODULE_DIR/$MODULE_ORIGINAL" "./lisp/$MODULE_RENAMED"

cask build
)
6 changes: 4 additions & 2 deletions bin/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Push-Location $project_root

cargo build --all $extra

Pop-Location

Copy-Item $module_dir\$module_name.dll $project_root\lisp\$module_renamed.dll

cask build

Pop-Location
2 changes: 1 addition & 1 deletion bin/test
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ if [[ $* == "watch" ]]; then
cargo watch -s bin/build -s bin/test
)
else
$EMACS --batch \
cask emacs --batch \
--directory "$PROJECT_ROOT/lisp" \
--directory "$PROJECT_ROOT/langs" \
-l ert \
Expand Down
2 changes: 1 addition & 1 deletion bin/test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ if ($args[0] -eq "watch") {
# https://github.com/PowerShell/PowerShell/issues/4002
# https://stackoverflow.com/questions/2095088/error-when-calling-3rd-party-executable-from-powershell-when-using-an-ide
$ErrorActionPreference = 'Continue'
emacs --batch `
cask emacs --batch `
--directory "$project_root\lisp" `
--directory "$project_root\langs" `
-l ert `
Expand Down
5 changes: 3 additions & 2 deletions langs/tree-sitter-langs-build.el
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ If VERSION and OS are not spcified, use the defaults of
(php "v0.16.1")
(python "v0.16.0")
(ruby "v0.16.1")
(rust "v0.16.0")
(rust "3e5ec5a")
(scala "v0.13.0")
(swift "a22fa5e")
(typescript "v0.16.1" ("typescript" "tsx")))
Expand Down Expand Up @@ -181,9 +181,10 @@ This function requires git and tree-sitter CLI."
(if (file-directory-p dir)
(let ((default-directory dir))
(tree-sitter-langs--call "git" "remote" "-v" "update"))
(tree-sitter-langs--call "git" "clone" "-v" repo dir))
(tree-sitter-langs--call "git" "clone" "-q" repo dir))
(let ((default-directory dir))
(tree-sitter-langs--call "git" "reset" "--hard" version)
(tree-sitter-langs--call "npm" "set" "progress=false")
;; TODO: Figure out why we need to skip `npm install' for some repos.
(ignore-errors
(tree-sitter-langs--call "npm" "install"))
Expand Down
48 changes: 43 additions & 5 deletions langs/tree-sitter-langs.el
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,37 @@

;;; Commentary:

;; This is a convenient bundle of language grammars for `tree-sitter'. It serves
;; as an interim distribution mechanism, until `tree-sitter' is widespread
;; enough for language major modes to include the definitions on their own.
;; This is a convenient bundle of language grammars and queries for
;; `tree-sitter'. It serves as an interim distribution mechanism, until
;; `tree-sitter' is widespread enough for language major modes to include these
;; definitions on their own.
;;
;; Basically it's a multi-step process:
;;
;; 1. `tree-sitter-langs' populates global registries of grammars and queries.
;; These global registries are defined by `tree-sitter-mode' and other
;; `tree-sitter'-based language-agnostic minor modes, to extend existing
;; major modes.
;;
;; 2. New `tree-sitter'-based language-specific minor modes use these global
;; registries to extend existing major modes.
;;
;; 3. Major modes adopt new `tree-sitter'-based features, and distribute the
;; grammars and queries on their own. They can either put these definitions
;; in the global registries, or keep using them only internally.

;;; Code:

(require 'cl-lib)

(require 'tree-sitter)
(require 'tree-sitter-load)
(require 'tree-sitter-hl)

(require 'tree-sitter-langs-build)

(eval-when-compile
(require 'pcase)
(require 'cl-lib))
(require 'pcase))

(defun tree-sitter-langs-ensure (lang-symbol)
"Return the language object identified by LANG-SYMBOL.
Expand Down Expand Up @@ -71,5 +88,26 @@ See `tree-sitter-langs-repos'."
(setf (map-elt tree-sitter-major-mode-language-alist major-mode)
lang-symbol))

(defun tree-sitter-langs--hl-default-patterns (lang-symbol)
"Return default syntax highlighting patterns for LANG-SYMBOL."
(let ((query-path (cl-reduce
(lambda (dir name) (expand-file-name name dir))
`("repos" ,(format "tree-sitter-%s" lang-symbol)
"queries" "highlights.scm")
:initial-value tree-sitter-langs--dir)))
(with-temp-buffer
(insert-file-contents query-path)
(buffer-string))))

(defun tree-sitter-langs--set-hl-default-patterns (&rest _args)
"Use syntax highlighting patterns provided by `tree-sitter-langs'."
(unless tree-sitter-hl-default-patterns
(let ((lang-symbol (alist-get major-mode tree-sitter-major-mode-language-alist)))
(setq tree-sitter-hl-default-patterns
(tree-sitter-langs--hl-default-patterns lang-symbol)))))

(advice-add 'tree-sitter-hl--setup :before
#'tree-sitter-langs--set-hl-default-patterns)

(provide 'tree-sitter-langs)
;;; tree-sitter-langs.el ends here
5 changes: 5 additions & 0 deletions lisp/test-files/change-case-region.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Change case of "this text" repeatedly.
unsafe {
input_function.call_unprotected((bytepos, point.line_number(), point.byte_column()))
.and_then(|v| v.into_rust())
}
5 changes: 5 additions & 0 deletions lisp/test-files/delete-non-ascii-text.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Delete the 8 chars next line.
// ấấấấấấấấ
unsafe {
input_function.call_unprotected((bytepos, point.line_number(), point.byte_column()))
}
6 changes: 6 additions & 0 deletions lisp/test-files/extend-region.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
macro_rules! impl_pred {}

// In evil's normal-mode, with point after `i`, or `;`, or at the end of the file, eval
// (font-lock-flush). A correct implementation would highlight `i` and `!`.
abc
impl_pred!(foo, bar);
Loading