Commit Graph

40262 Commits

Author SHA1 Message Date
Andrew Dupont
033f5c6498 Update grammar-registry and grammar-selector…
…to prefer new-tree-sitter grammars when the experimental setting is opted into,
and ignore them when it isn't.
2023-03-30 12:14:58 -07:00
Andrew Dupont
1fa034067e Highlight imports identically in TypeScript/TSX as in JavaScript 2023-03-29 17:12:29 -07:00
Andrew Dupont
253f514581 Fix formatting 2023-03-29 12:30:28 -07:00
Andrew Dupont
ae848b5f68 Add onlyIfOnSameRowAs and its opposite…
…to support the magical indentation logic for one-line conditionals.
2023-03-29 10:50:39 -07:00
Andrew Dupont
ba588195c5 Merge origin/master 2023-03-28 17:23:32 -07:00
Andrew Dupont
5326f77a9d ScopeResolver fixes and enhancements
Add `onlyIfRoot`. Fix `endAfterFirstMatchOf`.
2023-03-28 17:14:16 -07:00
Andrew Dupont
9ce12ab554 Add JSON grammar 2023-03-28 17:12:21 -07:00
Andrew Dupont
e13793034a Add C and C++ grammars 2023-03-28 17:03:42 -07:00
Andrew Dupont
bd822c2599 Update the CSS grammar 2023-03-28 15:53:07 -07:00
Andrew Dupont
a49338f8e8 Update the JavaScript grammar 2023-03-28 15:52:48 -07:00
Andrew Dupont
2a856736d7 Add Python grammar 2023-03-28 15:49:22 -07:00
Andrew Dupont
87b1e5d9c1 Update Ruby grammar 2023-03-28 15:32:58 -07:00
Andrew Dupont
5498f56e26 Add Rust grammar 2023-03-28 15:26:53 -07:00
Andrew Dupont
9226d626ac Get the tests passing again
Fixed logic in `scopeDescriptorForPosition` and stale cache in `FoldResolver`.
2023-03-28 14:27:37 -07:00
Andrew Dupont
ec12ca0474 Allow @match or @dedent to assert itself…
…even when it's not the first content on the line via `(#set! force true)`.
2023-03-28 11:40:34 -07:00
Andrew Dupont
4c9ce4fc6b Add new scope tests and some specs to cover them 2023-03-28 11:31:06 -07:00
Andrew Dupont
252618f2a4 Add suggestedIndentForBufferRows
…for suggesting the indent of a number of buffer rows at once.

The way `TextEditor` wants to auto-indent is by asking each row what its
indent level should be, then indenting each one in turn. This is because it
knows the language mode will probably determine row X's correct indentation by
using row X-1's indentation as a baseline, so there's no point in even calling
`suggestedIndentForBufferRow` for line X until X-1 is correctly indented.

This isn't ideal for us because each editor change will prompt a tree re-parse.
Instead, `suggestedIndentForBufferRows` will return the correct indentation
level for each row in a range without making any buffer changes.

It can do this because it tells `suggestedIndentForBufferRow` what the previous
row's indentation level is – hypothetically — so that it doesn't try to look it
up. Only the first row in the range compares its indentation to the _actual_
indentation of its preceding row; the rest of the rows figure out their
indentations relative to the hypothetical value we computed in the previous trip
through the loop.

This is paired with special logic in `TextEditor` to use this method instead of
its typical code path when asked to auto-indent multiple rows at once. Thus
we'll reduce the number of unscheduled tree parses from N (where N is the total
number of rows wanting to be auto-indented) to either zero or one.

Amazingly, I think this is the first time I've had to touch `text-editor.js` for
any reason.
2023-03-28 11:30:26 -07:00
Andrew Dupont
ece5101112 Add onlyIfDescendantOfNodeWithData and onlyIfNotDescendantOfNodeWithData
This hadn't occurred to me until I tried to mark illegal optional-chaining operators in certain contexts, much like how it's done in https://github.com/pulsar-edit/pulsar/pull/79. But it's a powerful way to match things regardless of their exact ancestry.
2023-03-27 17:09:59 -07:00
Andrew Dupont
07d1283882 Laying the ground for indentation overhaul
I spent a lot of time pursuing various things we could try to cut down on the amount of tree reparsing we'd need.

I haven't committed any of it, but those experiments did inform some changes that are present here. When wanting to perform an operation that would require a tree re-parse, we can now theoretically choose between (a) re-parsing and staying synchronous or (b) waiting until the next scheduled tree parse and going async.

The implications for how indentation works are too big to plow ahead with this approach, but it would be worth experimenting with. The vast majority of all our indentation decisions are prompted by a single keystroke, and in those cases there's no particular reason why we can't wait until a few milliseconds later when we're going to be re-parsing anyway.
2023-03-27 15:08:33 -07:00
confused_techie
75083faa59
Merge pull request #440 from machitgarha/patch-1
Fix spacing of PHP's "for …" snippet
2023-03-27 08:49:22 -07:00
Andrew Dupont
6de4da995b Optimizations for indents and folds
Spent a lot of time on indents today. Now that `nvim-treesitter` has renamed their indent captures, I figured I should switch to a system whose names made more sense to me.

`@indent_end` and `@branch` were too similar to keep as separate things, and have been consolidated into `@dedent`.

This system is pretty easy to write queries for, but it's awfully hard to _explain_, so I wonder if I have to go back to the drawing board here. I was convinced of its theoretical elegance, but then found a situation where I needed a different sort of capture, so I also invented `@dedent.next`. So now I'm not so sure.

Folds also got a look because they really did need some optimization. When we perform a transaction in the editor, we invalidate the folds cache, and since we know we'll end up querying against each of those lines individually, we can pre-capture each range with a folds query and save some time.

The worst thing about indents is the prospect of needing to re-parse the tree separate from the ordinary update process, since the editor calls `suggestedIndentForBufferRow` before the editor transaction finishes. It's not a bottleneck yet, but it could be if a given tree-sitter grammar were particularly slow. We can at least re-use the same tree when one of the `suggestedIndent` methods calls another.
2023-03-24 23:01:59 -07:00
Mohammad Amin Chitgarha
3da357d75f
Fix spacing of PHP's "for …" snippet 2023-03-24 09:55:59 +03:30
Andrew Dupont
a77915c032 Fix the names of ERB and EJS grammars 2023-03-23 22:39:59 -07:00
Andrew Dupont
a864ac0189 Disable language-todo and language-hyperlink injections…
…until they can be made faster.
2023-03-23 22:37:42 -07:00
Andrew Dupont
571e4afa43 Clean up JSDoc highlighting 2023-03-23 22:37:05 -07:00
Andrew Dupont
5f022dc7bd Clean up the JavaScript queries 2023-03-23 22:31:21 -07:00
Andrew Dupont
3232a6303c Fix endAt — new requirement that adjustments can't go beyond the original node's range 2023-03-23 22:16:43 -07:00
Maurício Szabo
03eace7280
Merge pull request #414 from pulsar-edit/s985-debian-maintainer
Update resources metadata
2023-03-23 22:02:24 -03:00
Andrew Dupont
328ef822a8 Add shell script web-tree-sitter grammar 2023-03-23 17:35:41 -07:00
Andrew Dupont
0be188fc9a Add TypeScript and TSX grammars
These two sets of query files share a lot of rules. I don't love the duplication. But it'll do for now.
2023-03-23 17:33:25 -07:00
Andrew Dupont
68d438b981 Add web-tree-sitter implementation of Java grammar 2023-03-23 16:21:01 -07:00
Andrew Dupont
7036b81db5 Fix issue where a change to the buffer was under-invalidating the highlighting…
…because we had no way of realizing how much of the buffer was affected by a change.

This was a worst-case scenario: consider a multiline JavaDoc-style comment — i.e., staring with `/**`. Imagine a `highlights.scm` that uses `#match?` to scope it as either `comment.block` or `comment.block.documentation` based on the presence or absence of that second asterisk. Now imagine you remove that second asterisk to make it an ordinary block comment.

If the tree-sitter parser understands the difference between these things, and gives them different node types, there's no problem, because it'll tell you which ranges need new highlighting based on syntactic changes. But if the change merely means a different scope should be applied — like if you highlight documentation comments differently from block comments — the whole comment won't get re-scoped and re-highlighted, because the highlights query isn't consulted until after we decide how much to invalidate. In a Java file, only the line you edited would get invalidated, so the rest of the block comment would remain the wrong color.

An ideal solution here would be to

  (a) recognize when a buffer edit will cause a capture to `#match?` differently from how it does now; then
  (b) invalidate that range so as to get it re-highlighted.

The “problem” is that we don't run the highlights query until the display layer asks us to tell it what to re-highlight, plus we retain no data structure such that we can compare old-versus-new and see which things are different. But that's less of a problem and more of a design decision made in order to deliver acceptable performance and to keep that costly work in WASM-land where it belongs.

The solution I arrived at is to

  (a) detect the range of the deepest single node that has been affected by an edit, and
  (b) ensure sure we invalidate at least that much of the buffer when we make a change.

In most cases, this will not even cause more syntax highlighting to take place; Pulsar always seems to re-highlight at least the entire row that we're on when we insert as little as a single character.

This does put some limits on how people can use `#match?`, but those are prudent limits anyway. Imagine deciding to scope things differently based on the text contained in a distant descendant, or even in a _sibling_. These are footguns.

If we really didn't like this and needed to solve it in a more general way, we could invent a new kind of specialized SCM file called `invalidations.scm`, and define captures for any kind of node that needs to be invalidated if an arbitrary change happens within it. We could run that query as part of the process of evaluating which ranges to re-highlight. Folks would want to do this sparingly, but if there were no other way to get the kind of highlighting needed in a particular grammar, then it would be a necessary evil.
2023-03-23 16:07:09 -07:00
Andrew Dupont
6f50399ea2 Streamline behavior around when injections include their root scope
An injection layer will include its root scope over its entire extent — i.e., whatever node is the root of its injection point — by default.

You can change the injected language's scope name with the new `languageScope` option on `addInjectionPoint`, but more useful is the ability to set it to `null` and bypass this behavior.

That's the right thing to do for the builtin injections `text.todo` and `text.hyperlink`, or else their scopes would always be present.

(This is a pain in the ass and I'm not 100% sure we've found the right solution. Pretend there's an injection for an embedded language like ERB; it'd inject into a bunch of disparate ranges, but still apply a scope over the entire extent, even the ranges where it's not active. The alternative — defining start/end scope boundaries for each of the disjoint ranges — is pretty chaotic in its own right, since those ranges tend to ignore things like whitespace. I would want such a language to set `languageScope: null`, then set its root scope via capture at whatever level of granularity makes sense for that language.)
2023-03-23 13:00:02 -07:00
Andrew Dupont
35f48a6022 Add @match capture for indents.scm
…for defining an indentation level relative to that of another line.

In rare cases where the indentation level of row X isn't just that of X-1 _plus or minus one_, the `@match` capture lets us specify when a line should match up exactly with another line.

Needs `(#set! matchIndentOf foo)`, where `foo` is a node descriptor. Will use the indentation level at the start of the specified node. (Might change this to accept a position descriptor.)

Optionally accepts `(#set! offsetIndent X)`, where X is any integer; allows us to say (e.g.) “indent one level deeper than X.”
2023-03-23 12:52:24 -07:00
Andrew Dupont
de40cabb78 Fix when no indents queries are available 2023-03-21 16:14:43 -07:00
Andrew Dupont
a284f11b04 Add suggestedIndentForBufferRow spec 2023-03-21 13:44:25 -07:00
Andrew Dupont
712c1650d8 Oops 2023-03-21 13:43:52 -07:00
Andrew Dupont
ac07eb0ea2 Fix function name 2023-03-21 13:00:07 -07:00
Andrew Dupont
f8fef24263 Move ScopeResolver to its own file…
…and write some specs for it.
2023-03-21 12:59:36 -07:00
Andrew Dupont
2cb7cb4ad6 Add a closest function to tree-sitter nodes…
…because `autocomplete-html` expects it to be there, hence other packages might as well.
2023-03-21 12:58:49 -07:00
Andrew Dupont
7736576a7f Fix getRangeForSyntaxNode predicate usage
The `bracket-matcher` package was assuming that `getSyntaxNodeForPosition`'s second argument — the test predicate — would stop running as soon as we found our match, and was using it to assign `startTag` and `endTag` variables. This is a fair assumption to make. So we shouldn't run the predicate until we're prepared to return immediately as soon as we find a match. That means putting _all_ candidates into a list, sorting that list from smallest to largest, and only then running the predicate.
2023-03-21 11:43:29 -07:00
Andrew Dupont
8637a75b19 Merge feature/modernize-tree-sitter 2023-03-20 16:04:04 -07:00
Andrew Dupont
80680de42e Move some stuff around in wasm-tree-sitter-language-mode.js 2023-03-20 16:01:26 -07:00
Andrew Dupont
376a2ba33f Add tree-sitter-todo parser for injecting into comments
Originally tried to use `tree-sitter-comment` (https://github.com/stsewd/tree-sitter-comment), but the syntax used there is stricter; eventually used it as reference to write something simpler. Works basically identically to the existing `language-todo` TM-style grammar.
2023-03-20 15:59:48 -07:00
Andrew Dupont
f4c1733021 Add modern-tree-sitter-hyperlink grammar for highlighting URLs
The tree-sitter-hyperlink parser is of my own invention and is quite rudimentary at this point, but it would be nice if it supported more of the stuff that the TM-style hyperlink grammar supports.
2023-03-20 15:54:40 -07:00
Andrew Dupont
9b1b23784a Add modern-tree-sitter versions of HTML and CSS grammars 2023-03-20 15:35:33 -07:00
Andrew Dupont
62e14f9baa Add wasm-tree-sitter-language-mode-spec.js
Watch these tests fail less and less over the next few days as I add more grammars!
2023-03-20 10:50:36 -07:00
Andrew Dupont
10e3855a6a Change the signature of WASMTreeSitterLanguageMode
…to match `TreeSitterLanguageMode`.
2023-03-20 10:49:52 -07:00
DeeDeeG
ae25fb9cf2
Merge pull request #434 from pulsar-edit/cirrus-install-ppm-deps-with-yarn
Cirrus: Windows: install ppm deps with Yarn
2023-03-20 03:14:05 -04:00
DeeDeeG
957cf836d0 Cirrus: Windows: install ppm deps with Yarn
Effectively: install ppm's dependencies (and run its postinstall
scripts) with Yarn, not npm, on Windows.

This makes the installation of ppm's dependencies consistently use
Yarn, not npm, in Cirrus CI. Consistent for all OSes/arches we build
for in Cirrus.

(* Although, at some level the postinstall scripts are run via npm as
a subprocess of node as a subprocess of Yarn in a shell/console
sub-process... Yes, in my opinion, ppm's postinstall scripts are way
too complicated...)

ALSO: This fixes an oversight in PR 239 where the build script of the
wrong project (ppm instead of core) was being run at one point, again
on Windows.

So, this should make it so Pulsar's core dependencies are built for
the correct Electron version instead of built for Node... Oops!
2023-03-19 22:27:07 -04:00