Merge from origin/emacs-29
4520f09dd8
; * admin/git-bisect-start: Update failing commits2569ede9c4
Update to Org 9.6-81-g563a43d9ed736f0a
ruby-ts-mode: Remove some currently unused functions4561844720
ruby-ts-mode: Highlight singleton method definitions and ...0562006da3
Add ruby-ts-mode84e7c2fbc8
Fix fontification of C++ reference return types (bug#60441)1864b65af6
; Minor fix for treesit--install-language-grammar-1 (bug#...8994f87ad4
Adjust function-call fontification in csharp-ts-mode (bug...411647a3f6
; Fix NEWS.7b0b17df67
Rewrite Antinews in ELisp manual for Emacs 29f12f72b0e0
; * lisp/simple.el (primitive-undo): Clarify error messag...7fd822e7f5
Update Antinews in the user manual for Emacs 29da77d70dee
; * test/lisp/emacs-lisp/copyright-tests.el: Fix and futu...2baf9e107c
Fix shortdoc-tests failure with respect to regexp-opt-cha...5aeb8de32e
; Fix copyright years in 2 more files. # Conflicts: # etc/NEWS
This commit is contained in:
commit
c209802f7b
27 changed files with 1639 additions and 351 deletions
|
@ -82,7 +82,7 @@ done
|
|||
# SKIP-BRANCH 58cc931e92ece70c3e64131ee12a799d65409100
|
||||
|
||||
## The list below is the exhaustive list of all commits between Dec 1
|
||||
## 2016 and Nov 30 2022 on which building Emacs with the default
|
||||
## 2016 and Dec 31 2022 on which building Emacs with the default
|
||||
## options, on a GNU/Linux computer and with GCC, fails. It is
|
||||
## possible (though unlikely) that building Emacs with non-default
|
||||
## options, with other compilers, or on other platforms, would succeed
|
||||
|
@ -1637,3 +1637,40 @@ $REAL_GIT bisect skip $(cat $0 | grep '^# SKIP-SINGLE ' | sed 's/^# SKIP-SINGLE
|
|||
# SKIP-SINGLE 4552b01d8c8052f607dca2fcddcf7b2e270f1db6
|
||||
# SKIP-SINGLE b6568c1389128d47538b646d940427949ddf58d0
|
||||
# SKIP-SINGLE 6d5b34d9de7b2f1b346d9aff123ad20c942166dc
|
||||
# SKIP-SINGLE d9d90666f545dc25be63c1b16c030ce1aa96510e
|
||||
# SKIP-SINGLE e645bcc26d468ab6b8e16b6160c203c5db70ec6b
|
||||
# SKIP-SINGLE 0aea1cf8190aa804a0d11a67b4a3cb4b715ae82d
|
||||
# SKIP-SINGLE 7e6d1d1c47196bf1bb5254f5c9014e25bdaf9833
|
||||
# SKIP-SINGLE 784e509bded0fe41dd9908022a92c54ac8c21a2c
|
||||
# SKIP-SINGLE bc4cbbcc57a56a23c64576c8c23ecf6afb1c747b
|
||||
# SKIP-SINGLE 523261b454058d0b28df2c3de1eab55fe378aa69
|
||||
# SKIP-SINGLE 29d23b7fa00ed8263baa060d487b526d51fa6986
|
||||
# SKIP-SINGLE 9371d488be62a37788b499a7e44b1f5db158e212
|
||||
# SKIP-SINGLE 60418e6f09c67924e3e05eb4948e109d8f7c4073
|
||||
# SKIP-SINGLE 9153cf8158489d387a6a0d9d0ede9a2528c35f0a
|
||||
# SKIP-SINGLE d11e34ce76aac8680337f247419657e042e4cf34
|
||||
# SKIP-SINGLE 2541bec21bf3cf090071e434dac170d52394594e
|
||||
# SKIP-SINGLE 007e66bccb2cb8382158e5e24727fd1b4478cd69
|
||||
# SKIP-SINGLE 753b7a1cff6b8ce2367a94d27b615ac31f1067ba
|
||||
# SKIP-SINGLE 7c63b632e4e2241a28f08015cc981a72e18d7867
|
||||
# SKIP-SINGLE 91ae9f3d12885373d38c3e8d693f7dc210f9d471
|
||||
# SKIP-SINGLE 314cbef84944145e2160736ce32812403ed99cd9
|
||||
# SKIP-SINGLE 1a88a28ace24c8b4fb1e4780948b50dd37ada539
|
||||
# SKIP-SINGLE 98327e371938033f7ccefd1c5226cd102cb29ad1
|
||||
# SKIP-SINGLE 9d814bea4600ac28dcdbf9caf386467551d7d9be
|
||||
# SKIP-SINGLE 73769dc2b872441eb0b8565e1090e97fc0b5d521
|
||||
# SKIP-SINGLE 283043621756fd004906ecdd5ba829a47cb3fc57
|
||||
# SKIP-SINGLE 05ece1eb8b7ce28d366d02df89449d453be8d37e
|
||||
# SKIP-SINGLE 248c13dcfe1b9618811a6fe67e967b25b1a8f139
|
||||
# SKIP-SINGLE 38c35bf0f6a938001dfecbe439addf8fb62897c6
|
||||
# SKIP-SINGLE 9065d745151e1995b80a1f4d5a04e2af111ad928
|
||||
# SKIP-SINGLE e78e69b33189c653d1588b810283969ac3cca137
|
||||
# SKIP-SINGLE 909091d7578b7225601b202fb9257dedae879e9a
|
||||
# SKIP-SINGLE 706ed85285515e7047e16608815c1d02d4907b07
|
||||
# SKIP-SINGLE 7013b0179cbe5cce19e114d7673770d1425d3005
|
||||
# SKIP-SINGLE 2de25accaf31aef643557ec476041c770fc7ac15
|
||||
# SKIP-SINGLE 2b1fdbffcb595bcd72fa9aa3db674c6985042bcb
|
||||
# SKIP-SINGLE 1480865e641b06d570f5ab56011f8e3e5481da7d
|
||||
# SKIP-SINGLE 8c13e8497821881b5197a1717e9e53b9991859d0
|
||||
# SKIP-SINGLE a6db8464e150c49724c71c5969b97f205ee2dec5
|
||||
# SKIP-SINGLE cfbfd393b450d4eb7ac0b7922b44208688553c9e
|
||||
|
|
|
@ -4,134 +4,154 @@
|
|||
@c See file emacs.texi for copying conditions.
|
||||
|
||||
@node Antinews
|
||||
@appendix Emacs 27 Antinews
|
||||
@appendix Emacs 28 Antinews
|
||||
@c Update the emacs.texi Antinews menu entry with the above version number.
|
||||
|
||||
For those users who live backwards in time, here is information
|
||||
about downgrading to Emacs version 27.2. We hope you will enjoy the
|
||||
about downgrading to Emacs version 28.2. We hope you will enjoy the
|
||||
greater simplicity that results from the absence of many @w{Emacs
|
||||
@value{EMACSVER}} features.
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Emacs can no longer be built with support of native compilation of
|
||||
Lisp programs. This means Emacs builds much faster, and the problems
|
||||
that came with native compilation: the need to have GCC and Binutils
|
||||
installed, the complications of managing your @file{eln-cache}
|
||||
directories---all of that is now future history. The simplicity and
|
||||
elegance of the Emacs byte-compiled code is now restored in all of its
|
||||
pristine beauty.
|
||||
Like its newer releases, Emacs 28 can still be built with support of
|
||||
native compilation of Lisp programs. However, in preparation for
|
||||
removal of this feature in some previous version, we've deleted the
|
||||
capability of ahead-of-time native compilation of all the Lisp files
|
||||
that come with Emacs. This makes the Emacs build process much faster.
|
||||
|
||||
@item
|
||||
Emacs no longer builds by default with Cairo, even if it's present.
|
||||
The warnings about not using HarfBuzz are also gone, in preparation
|
||||
for complete removal of HarfBuzz support in previous Emacs versions.
|
||||
Fancy text shaping and display is becoming less important as you move
|
||||
back in time. The @code{ftx} font backend is again part of Emacs, for
|
||||
the same reasons.
|
||||
Emacs can no longer be built with the tree-sitter library, so you no
|
||||
longer will need to look for and install the grammar libraries for
|
||||
the languages in which you want to program. Similarly, all the modes
|
||||
that are based on the tree-sitter library were deleted, leaving you
|
||||
with just one major mode for every supported programming language: no
|
||||
more need to decide whether to turn the tree-sitter supported modes on
|
||||
and try using their parser-based fontification, indentation, and other
|
||||
features. For some languages and file types, this means no major mode
|
||||
at all, leaving you with the venerable Fundamental mode as the
|
||||
natural, high-performance choice. For example, Go, Rust, and CMake
|
||||
files no longer have any major modes for editing their files ---
|
||||
another milestone towards a simpler, leaner Emacs.
|
||||
|
||||
@item
|
||||
Emacs once again supports versions 5.3 and older OpenBSD systems,
|
||||
which will be needed as you move back in time.
|
||||
Built-in support for accessing SQLite databases was removed. You can
|
||||
now again edit SQLite files as simple binary files, which Emacs is
|
||||
quite capable to support, as it always did.
|
||||
|
||||
@item
|
||||
We've dropped support for Secure Computing filter on GNU/Linux. The
|
||||
past world is much more secure than the present, so the complexities
|
||||
related with this stuff, which can only be explained by severe
|
||||
paranoia, are no longer justified.
|
||||
As a gesture to users of the Haiku operating system, we've dropped the
|
||||
code which allowed Emacs to be built on that OS@. We expect Haiku
|
||||
users to enjoy the much simpler editors they have for editing their
|
||||
files.
|
||||
|
||||
@item
|
||||
Emacs reverted back to supporting Unicode 13.x, since the following
|
||||
versions of the standards are not yet published where you are going.
|
||||
The @samp{emoji} script and the support for displaying Emoji sequences
|
||||
were removed for the same reasons: no one will produce them in the
|
||||
past.
|
||||
Support for XInput2 input events on X is gone. We think the
|
||||
traditional X input events are more than enough, certainly so as you
|
||||
move back in time, where XInput2 will eventually be removed from X as
|
||||
well, once the maintainers of the X Windows system realize the utter
|
||||
futility of supporting fancy input mechanisms.
|
||||
|
||||
@item
|
||||
Mode-specific commands and the @kbd{M-S-x} command that invokes them
|
||||
were removed. As you move back in time, the command set in Emacs
|
||||
becomes smaller, so any such filtering of applicable commands just
|
||||
gets in the way.
|
||||
The ``pure GTK'' (a.k.a.@: @acronym{PGTK}) configuration of Emacs is
|
||||
no longer supported. This is in anticipation of the complete removal
|
||||
of the GTK toolkit support from Emacs, and in accordance with our
|
||||
expectation that GTK will cease to exist as you move back in time. We
|
||||
plan on removing support for all the other toolkits as well, leaving
|
||||
only the pure X build with our own widgets as the single supported GUI
|
||||
configuration on X.
|
||||
|
||||
@item
|
||||
We have removed the system for displaying documentation of groups of
|
||||
related functions, the @kbd{shortdoc-display-group} command to go with
|
||||
it, and the corresponding ``See also'' button in the @file{*Help*}
|
||||
buffer. That should make searching for certain functions simpler:
|
||||
just use the venerable @samp{apropos} commands.
|
||||
The @option{--init-directory} command-line option was removed, as
|
||||
initializing Emacs with init files of another user is a preposterous
|
||||
idea anyway.
|
||||
|
||||
@item
|
||||
The @code{context-menu-mode} was removed, and with it the context
|
||||
menus popped by pressing the right mouse button. This is one small
|
||||
step towards freeing Emacs (and eventually, the whole world of
|
||||
computing) from the tyranny of the GUI pointing devices in general,
|
||||
and moving back to the simplicity of text-mode user interfaces.
|
||||
Down with mice and other rodents!
|
||||
In line with simplifying and eventually removing the
|
||||
native-compilation option, we've deleted the
|
||||
@code{inhibit-automatic-native-compilation} variable and its support
|
||||
code. This greatly simplifies how native compilation works and makes
|
||||
your configure-time decision regarding native compilation in Emacs
|
||||
clear-cut: either Emacs always compiles Lisp to native code before
|
||||
using it, or it never does so; no more half measures and special
|
||||
exceptions. For similar reasons, @code{native-compile-prune-cache}
|
||||
and @code{startup-redirect-eln-cache} features are no longer part of
|
||||
Emacs.
|
||||
|
||||
@item
|
||||
The commands @kbd{C-x 4 4} and @kbd{C-x 5 5} for displaying the
|
||||
results in a new window/frame re gone. We are quite certain that
|
||||
creating a new window/frame before running a command is much simpler,
|
||||
and doesn't require a complication of a new prefix.
|
||||
We've deleted the special code and features which allowed Emacs to
|
||||
present decent performance and responsiveness when editing files with
|
||||
very long lines. Such files become more and more rare as time goes
|
||||
back, and so having all this tricky code in Emacs for their benefit
|
||||
was deemed an unnecessary complication.
|
||||
|
||||
@item
|
||||
The behavior of active minibuffers when switching frames is now the
|
||||
perfect mess it should be: sometimes the minibuffer moves to the new
|
||||
selected frame, sometimes it doesn't, and sometimes you get an error.
|
||||
This makes Emacs usage much more fun, as you get to guess the result,
|
||||
instead of having it boringly consistent.
|
||||
Emacs dropped support for Eglot and the LSP servers. We decided that
|
||||
the built-in ways of analyzing source code are more than enough as you
|
||||
move back in time.
|
||||
|
||||
@item
|
||||
Compact mode-line display mode has been removed. The items displayed
|
||||
on the mode line are now always in the same place, and if there's not
|
||||
enough space for them, they are not displayed at all, instead of being
|
||||
confusingly displayed in a different position. You no longer need to
|
||||
think twice where to find a particular mode-line element on display.
|
||||
Commands to scale and rotate images are once again bound to single
|
||||
keys like @kbd{+}, @kbd{-}, and @kbd{r}, which makes them much easier
|
||||
to type. As for the risk of typing these by mistake, we don't believe
|
||||
Emacs users make typing mistakes, especially as they move back in
|
||||
time and become younger and younger.
|
||||
|
||||
@item
|
||||
Many commands and options related to tab bars were removed, including
|
||||
(but not limited to) frame-specific appearance of tab bars, the
|
||||
@code{tab-bar-format} option, the @kbd{C-x t n}, @kbd{C-x t N},
|
||||
@kbd{C-x t M}, and @kbd{C-x t G} commands, and many mouse gestures on
|
||||
the tab bar. We are going to delete the tab bar support from Emacs in
|
||||
one of the past versions, and this is a step in that direction.
|
||||
To simplify typing popular commands, we've rebound the @w{@kbd{C-x 8 . .}}
|
||||
back to @w{@kbd{C-x 8 .}} and @w{@kbd{C-x 8 = =}} back to @w{@kbd{C-x 8 =}}.
|
||||
There's no need for fancier, longer key sequences, as moving back in
|
||||
time means we will have fewer and fewer commands to bind to them in
|
||||
the first place.
|
||||
|
||||
@item
|
||||
The ``transient'' input methods have been removed; use @kbd{C-\} to
|
||||
turn input methods on and off instead. This is in preparation for
|
||||
complete removal of input methods from Emacs in version 19, and
|
||||
consistent with the fact that the number of input methods we support
|
||||
becomes smaller as you move back in time.
|
||||
If you inadvertently kill the @file{*scratch*} buffer, Emacs will
|
||||
recreate it in Fundamental mode, not in Lisp Interaction mode. You
|
||||
get to turn on the mode you like yourself. Our long-term plans for
|
||||
past Emacs releases is to remove the recreation of @file{*scratch*}
|
||||
altogether, and this is the first step in that direction.
|
||||
|
||||
@item
|
||||
We disabled @code{show-paren-mode} by default, since we think the
|
||||
venerable @code{blink-matching-paren} feature is more than enough, and
|
||||
better fits the simplicity of past Emacs versions. It will definitely
|
||||
be better when colors are removed from Emacs in the distant past.
|
||||
|
||||
For the same reason, sub-groups in interactive regexp searches are no
|
||||
longer highlighted in distinct colors.
|
||||
Support for @code{rlogin} and @code{rsh} protocols are back, since we
|
||||
expect them to become more and more important and popular as you move
|
||||
back in time.
|
||||
|
||||
@item
|
||||
On our permanent quest for simplifying Emacs, we've removed the Ispell
|
||||
command @code{ispell-comment-or-string-at-point}; the old-time friend
|
||||
@code{ispell-comments-and-strings} should suffice.
|
||||
In preparation for eventual removal of Unicode support from Emacs,
|
||||
we've downgraded our Unicode support to version 14.0.
|
||||
|
||||
@item
|
||||
Many Gnus commands and options were deemed to unnecessarily complicate
|
||||
the use of Gnus (which is too complex to begin with), and thus were
|
||||
removed. This includes @code{gnus-topic-display-predicate},
|
||||
@code{gnus-process-mark-toggle}, @code{gnus-registry-register-all},
|
||||
@code{gnus-paging-select-next}, and many others. The @code{nnselect}
|
||||
backend was deleted for the same reason.
|
||||
You can no longer change the size of the font globally. Since Emacs
|
||||
will at some past date remove all support for variable-size fonts,
|
||||
having such commands is a luxury we are better without.
|
||||
|
||||
@item
|
||||
The @file{project.el} package have been redesigned to remove many
|
||||
unnecessary features, so that just the bare essentials remain. We
|
||||
plan on removing this package from Emacs in a previous version, but
|
||||
decided to begin with removing some extra features first.
|
||||
On our permanent quest for simplifying Emacs, we've removed the
|
||||
commands @code{duplicate-line} and @code{duplicate-dwim}; the old-time
|
||||
friends @kbd{M-w} and @kbd{C-y} (typed one or more times) should
|
||||
suffice. The command @code{rename-visited-file} is gone for the same
|
||||
reason.
|
||||
|
||||
@item
|
||||
We've deleted many commands related to Emoji, which were bound in the
|
||||
@kbd{C-x 8 e} prefix keymap. We decided that the ability to type
|
||||
Emoji sequences using @kbd{C-x 8 @key{RET}} is enough, and actually
|
||||
serves our users better by requiring them to know the codepoints of
|
||||
the sequences they want to type.
|
||||
|
||||
@item
|
||||
We dropped support for many scripts and input methods, especially old
|
||||
scripts that no one uses anyway. For similar reasons, Greek and
|
||||
Ukrainian translations of the Emacs tutorial are not available
|
||||
anymore.
|
||||
|
||||
@item
|
||||
@file{package.el} can no longer fetch source code of packages from
|
||||
their VCS repositories. We think command-line tools like Git should
|
||||
be enough to allow you to clone their repositories. So we deleted
|
||||
the @code{package-vc-install} command and other similar commands.
|
||||
|
||||
@item
|
||||
To keep up with decreasing computer memory capacity and disk space, many
|
||||
other functions and files have been eliminated in Emacs 27.2.
|
||||
other functions and files have been eliminated in Emacs 28.2.
|
||||
@end itemize
|
||||
|
|
|
@ -220,7 +220,7 @@ Appendices
|
|||
* GNU Free Documentation License:: The license for this documentation.
|
||||
* Emacs Invocation:: Hairy startup options.
|
||||
* X Resources:: X resources for customizing Emacs.
|
||||
* Antinews:: Information about Emacs version 27.
|
||||
* Antinews:: Information about Emacs version 28.
|
||||
* Mac OS / GNUstep:: Using Emacs under macOS and GNUstep.
|
||||
* Haiku:: Using Emacs on Haiku.
|
||||
* Microsoft Windows:: Using Emacs on Microsoft Windows and MS-DOS.
|
||||
|
|
|
@ -6,179 +6,182 @@
|
|||
@c This node must have no pointers.
|
||||
|
||||
@node Antinews
|
||||
@appendix Emacs 27 Antinews
|
||||
@appendix Emacs 28 Antinews
|
||||
@c Update the elisp.texi Antinews menu entry with the above version number.
|
||||
|
||||
For those users who live backwards in time, here is information about
|
||||
downgrading to Emacs version 27.2. We hope you will enjoy the greater
|
||||
downgrading to Emacs version 28.2. We hope you will enjoy the greater
|
||||
simplicity that results from the absence of many @w{Emacs
|
||||
@value{EMACSVER}} features.
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
The annoying @code{lexical-binding} local variable now heeds the
|
||||
value of @code{enable-local-variables}: if it's @code{nil}, the
|
||||
@code{lexical-binding} cookie is ignored. We are working hard on
|
||||
removing the lexical-binding support in some past Emacs version, and
|
||||
this small step advances us back to that change.
|
||||
The implementation of overlays is back to its simple, time-proven
|
||||
storage in a pair of linear linked lists centered around some buffer
|
||||
position. No more fancy interval trees and suchlikes. Lisp programs
|
||||
that use overlays once again need to recenter overlays around the
|
||||
buffer position of interest, and display-related features should again
|
||||
make sure they don't use too many overlays in a buffer, lest redisplay
|
||||
will be too slow.
|
||||
|
||||
@item
|
||||
The @code{load-dangerous-libraries} variable is not obsolete, as it
|
||||
must be used to allow loading Lisp compiled by XEmacs, which will
|
||||
become more and more important as you move back in time.
|
||||
Several functions stopped the annoying conversion of quotes and key
|
||||
sequences by no longer calling @code{substitute-command-keys}. One
|
||||
prominent example is @code{format-prompt} and all its many callers.
|
||||
This makes the strings they produce much more predictable, returning
|
||||
to you, the Lisp programmer, control on which punctuation characters
|
||||
will appear in the text presented to the users. For similar reasons,
|
||||
the @code{substitute-quotes} function was deleted.
|
||||
|
||||
@item
|
||||
The optional @var{modes} argument of @code{interactive} is not
|
||||
supported, and every command is deemed applicable to any major mode.
|
||||
We believe this makes the life of Lisp programmers much simpler, as
|
||||
there's now no need to tag commands with the modes where they make
|
||||
sense.
|
||||
The venerable @code{buffer-modified-p} function again reliably returns
|
||||
either @code{nil} or @code{t}, not any other confusing values.
|
||||
|
||||
@item
|
||||
Shorthands for Lisp symbols have been removed, which makes loading
|
||||
Lisp files and handling Lisp symbols much simpler and more efficient.
|
||||
This is important for decent performance on slower CPUs as you move
|
||||
back in time.
|
||||
The support for @samp{medium} weight of fonts was dropped. Emacs now
|
||||
considers @samp{medium} and @samp{regular} weights to be the same. We
|
||||
believe this will simplify your font setup, since there's no longer a
|
||||
need to worry about fonts that support @samp{regular} weight, but not
|
||||
the @samp{medium} one, or vice versa: either one will do!
|
||||
|
||||
@item
|
||||
To reduce the amount of code in Emacs related to unimportant features,
|
||||
we've removed the variables @code{global-minor-modes} and
|
||||
@code{local-minor-modes}. If your Lisp program needs to determine
|
||||
whether some minor mode is in effect, it will have to test explicitly
|
||||
for every mode. We don't expect anyone to miss those fancy variables.
|
||||
we've removed the function @code{compiled-function-p}. Lisp programs
|
||||
are expected to test explicitly for the relevant types of function
|
||||
objects: built-in, byte-compiled, and natively-compiled. For the same
|
||||
reasons we deleted the functions @code{pos-bol}, @code{pos-eol},
|
||||
@code{file-attribute-file-identifier}, and quite a few others. We
|
||||
don't expect anyone to miss those fancy functions.
|
||||
|
||||
@item
|
||||
The default preference for servicing sub-processes that produce output
|
||||
at a high rate, and the associated variable
|
||||
@code{process-prioritize-lower-fds}, have been removed. Moving back
|
||||
in time means fewer and fewer programs can produce such high-rate
|
||||
output, so this features becomes just useless crud.
|
||||
The timeout used by @code{x-show-tip} can no longer be specified by
|
||||
Lisp programs; it is hard-coded in the function. This will lead to a
|
||||
simpler, easier maintained code, and no one should want to control the
|
||||
timeout after which the tip pops down.
|
||||
|
||||
@item
|
||||
The encodings that are variants of EBCDIC were removed. This includes
|
||||
@code{ibm256}, @code{ibm273}, and others---variants of the EBCDIC
|
||||
encoding tailored for some Japanese and European locales. You won't
|
||||
need those where you are going.
|
||||
The macro @code{setopt} was deleted; use @code{customize-variable}
|
||||
instead, or invoke the @code{:set} function from Lisp.
|
||||
|
||||
@item
|
||||
The ``Bindat type expression'' description language has been removed,
|
||||
as the existing data layout specifications are perfectly suited for
|
||||
this job.
|
||||
We removed the @code{lisp-directory} variable, as the value can be
|
||||
easily deduced from other similar variables, like
|
||||
@code{installation-directory} and @code{source-directory}, each one
|
||||
when it's relevant.
|
||||
|
||||
@item
|
||||
To simplify code and reduce complexity, we removed the capability of
|
||||
specifying the success handler in @code{condition-case} via the
|
||||
@code{:success} keyword. If you really need this feature (why would
|
||||
you?), you can always write some simple Lisp that has the same effect.
|
||||
To simplify code and reduce complexity, we deleted the functions
|
||||
@code{get-display-property} and @code{add-display-text-property}; use
|
||||
the generic @code{get-text-property} and @code{put-text-property}
|
||||
instead.
|
||||
|
||||
@item
|
||||
Emacs modules can no longer provide interactive functions, or install
|
||||
finalizers, nor open channels to existing pipe sub-processes. All
|
||||
this is extra ballast, especially since we plan on removing modules in
|
||||
some past Emacs version. The @code{make_unibyte_string} module API
|
||||
was removed for the same reason.
|
||||
Support for pinch input events and for modern drag-and-drop
|
||||
functionality on X was dropped. As you move back in time, these
|
||||
facilities will become less and less important, and will soon enough
|
||||
disappear, so there's no reason to keep them in Emacs.
|
||||
|
||||
@item
|
||||
To keep Emacs clean and elegant, we've removed the
|
||||
@code{print-integers-as-characters} option. Recognizing characters by
|
||||
their decimal codes is a basic requirement for Emacs Lisp programmers,
|
||||
and with the expected decrease in use of Unicode characters, this will
|
||||
be soon limited to ASCII only: surely something you all can master!
|
||||
To keep Emacs clean and elegant, we've removed the @file{textsec.el}
|
||||
library, with its facilities for checking whether some text is
|
||||
``suspicious''. We consider our users smart enough to detect
|
||||
maliciously modified text by just looking at it or by moving the
|
||||
cursor across it, and the whole idea that someone would wish to
|
||||
deliberately deceive Emacs users ridiculous and unworthy of
|
||||
complicating our elegant text-processing and display capabilities.
|
||||
|
||||
@item
|
||||
The optional @var{count} argument of the @code{directory-files}
|
||||
function has been removed. Extracting the first @var{n} members from
|
||||
the full list is trivial, so this is a significant simplification for
|
||||
an insignificant cost.
|
||||
The functions @code{keymap-set}, @code{keymap-global-set},
|
||||
@code{keymap-local-set}, @code{keymap-substitute},
|
||||
@code{keymap-lookup}, and some others were deleted. We have found the
|
||||
traditional @code{define-key}, @code{global-set-key},
|
||||
@code{local-set-key}, @code{substitute-key-definition}, and
|
||||
@code{key-binding} more than enough, and their minor inconsistencies
|
||||
in the syntax of keys they accept a source of endless fun in Emacs
|
||||
Lisp programming. Why make Emacs programming a dull place? For the
|
||||
same reasons we deleted @code{key-valid-p}, since we consider the
|
||||
permissive nature of @code{kbd} more in the spirit of Emacs Lisp.
|
||||
|
||||
@item
|
||||
Functions that create sub-processes and network connections no longer
|
||||
accept the @code{:coding} argument; use
|
||||
@code{set-process-coding-system} or bind
|
||||
@code{coding-system-for-read/write} instead: again, a significant
|
||||
reduction in Emacs complexity for little or no cost.
|
||||
Yanking of anything but plain text from other applications becomes
|
||||
more and more an unnecessary feature as you move back in time, so we
|
||||
dropped support for pasting media like HTML and images via the
|
||||
clipboard. If you @i{really} need to yank those into an Emacs buffer,
|
||||
you can go via a disk file.
|
||||
|
||||
@item
|
||||
We deleted from the macros @code{define-derived-mode} and
|
||||
@code{define-minor-mode} the code which allowed using the
|
||||
@code{:interactive} argument. The possibility of marking a mode
|
||||
non-interactive makes very little sense,
|
||||
We removed unnecessary functions @code{string-pixel-width} and
|
||||
@code{string-glyph-split}, as we consider it inappropriate for Lisp
|
||||
programs to do display layout calculations, where these functions come
|
||||
in handy. Display is for the display engine, written in C, and should
|
||||
stay there!
|
||||
|
||||
@item
|
||||
The possibility of having links to man pages in doc strings has been
|
||||
removed. Use plain text instead, if you need such references.
|
||||
Various new Xwidget functions, such as
|
||||
@code{xwidget-perform-lispy-event}, @code{xwidget-webkit-load-html},
|
||||
and @code{xwidget-webkit-back-forward-list}, were deleted as part of
|
||||
our continuing effort to gradually delete the entire Xwidget
|
||||
functionality in some previous release of Emacs.
|
||||
|
||||
@item
|
||||
Temporary buffers are no longer exempt from running any buffer-related
|
||||
hooks. Programs that don't want such hooks in some buffer can always
|
||||
disable it locally, whereas making that simpler complicates Emacs for
|
||||
no good reason.
|
||||
Setting the @code{:stderr} property of a process in a
|
||||
@code{make-process} call once again forces the process's connection to
|
||||
use pipes, not ptys, for all the standard streams --- a considerable
|
||||
simplification of this complex interface.
|
||||
|
||||
@item
|
||||
To keep the amount of Lisp functions from growing out of control, we
|
||||
deleted @code{string-equal-ignore-case}. Use @code{compare-strings}
|
||||
instead.
|
||||
|
||||
Several features that complicated the byte compiler have been removed:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
The checks for missing declarations of dynamic variables. This will
|
||||
continue making less and less sense as we move away of lexical-binding
|
||||
support.
|
||||
The warnings about quoting mistakes in documentation strings. You are
|
||||
expected to find such mistakes yourself, by eyeballing the resulting
|
||||
@file{*Help*} buffer display.
|
||||
|
||||
@item
|
||||
The ability of compiling symlinked @file{*.el} files, which is really
|
||||
gross: copy the files instead.
|
||||
|
||||
@item
|
||||
The warnings about too-wide doc strings---that is just a nuisance, as
|
||||
the programmers should be trusted to know what they are doing.
|
||||
@end itemize
|
||||
|
||||
|
||||
@item
|
||||
We deleted several features of the @code{pcase} macro, in accordance
|
||||
with our general plan to remove @code{pcase} from Emacs:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
The @code{cl-type} pattern.
|
||||
|
||||
@item
|
||||
the @code{pcase-setq} macro.
|
||||
|
||||
@item
|
||||
The @code{pcase-compile-patterns} function.
|
||||
The warnings about malformed @code{defcustom} types, like
|
||||
double-quoting symbols in @code{choice} lists.
|
||||
@end itemize
|
||||
|
||||
@item
|
||||
Some of the keywords used in Edebug specification lists were deemed to
|
||||
be of little use, and were therefore removed: @code{&interpose},
|
||||
@code{&error}, and @code{&name}. The long-term plane is for Emacs to
|
||||
drop Edebug entirely, leaving only the trusted Lisp debugger, and we
|
||||
continue working according to that plan.
|
||||
The macro @code{with-buffer-unmodified-if-unchanged} was deleted.
|
||||
Lisp programs that need to leave the buffer unmodified in these cases
|
||||
can always compare the text before and after the modifications.
|
||||
|
||||
@item
|
||||
The function @code{object-intervals} was dropped, as a Lisp program
|
||||
can easily collect the intervals of a buffer or a string by iterating
|
||||
through them one by one.
|
||||
The functions @code{string-edit} and @code{read-string-from-buffer}
|
||||
were removed, as we consider the fun of programming them anew every
|
||||
time an important part of the education of each Emacs Lisp developer.
|
||||
|
||||
@item
|
||||
We decided that the @code{require-theme} function is an unnecessary
|
||||
complication, so we deleted it. Lisp programs can easily search along
|
||||
@code{custom-theme-load-path} instead.
|
||||
We deleted the function @code{readablep} and the related variable
|
||||
@code{print-unreadable-function}, since no one is supposed to want to
|
||||
print unreadable Lisp objects.
|
||||
|
||||
@item
|
||||
The convenience functions @code{length<}, @code{length>}, and
|
||||
@code{length=} were removed, as using @code{length} followed by a
|
||||
comparison should be good enough for everyone, especially considering
|
||||
that the typical length of a list keeps going down as you move back
|
||||
through time.
|
||||
The facility for storing multisession variables was deleted as an
|
||||
unnecessary complication. With it are gone @code{multisession-value},
|
||||
@code{define-multisession-variable}, and
|
||||
@code{list-multisession-values}.
|
||||
|
||||
@item
|
||||
The variable @code{current-minibuffer-command} is no longer available,
|
||||
as we found little justification for keeping it.
|
||||
The support for the @code{cursor-face} text property was dropped. We
|
||||
consider the rest of the faces adequate for supporting this
|
||||
functionality.
|
||||
|
||||
@item
|
||||
The function @code{tooltip-show} dropped support for optional face
|
||||
arguments @code{text-face} and @code{default-face} that allow fancy
|
||||
control of the face of the tip text and top frame colors. We decided
|
||||
that tooltips should all look the same, to prevent user confusion.
|
||||
|
||||
@item
|
||||
As part of the ongoing quest for simplicity, many other functions and
|
||||
variables have been eliminated. Other functions and variables, that
|
||||
were declared obsolete since Emacs 23, have been added back, in
|
||||
preparation for releasing Emacs 23 in some distant past.
|
||||
were declared obsolete since Emacs 24, have been added back, in
|
||||
preparation for releasing Emacs 24 in some distant past.
|
||||
@end itemize
|
||||
|
|
|
@ -235,7 +235,7 @@ To view this manual in other formats, click
|
|||
|
||||
Appendices
|
||||
|
||||
* Antinews:: Info for users downgrading to Emacs 27.
|
||||
* Antinews:: Info for users downgrading to Emacs 28.
|
||||
* GNU Free Documentation License:: The license for this documentation.
|
||||
* GPL:: Conditions for copying and changing GNU Emacs.
|
||||
* Tips:: Advice and coding conventions for Emacs Lisp.
|
||||
|
|
15
etc/NEWS.29
15
etc/NEWS.29
|
@ -3261,6 +3261,11 @@ written in YAML. It is auto-enabled for files with the ".yaml" or
|
|||
A major mode based on the tree-sitter library for editing programs in
|
||||
the Rust language. It is auto-enabled for files with the ".rs" extension.
|
||||
|
||||
---
|
||||
*** New major mode 'ruby-ts-mode'.
|
||||
An optional major mode based on the tree-sitter library for editing
|
||||
programs in the Ruby language.
|
||||
|
||||
|
||||
* Incompatible Lisp Changes in Emacs 29.1
|
||||
|
||||
|
@ -3812,21 +3817,21 @@ Standard.
|
|||
** seq
|
||||
|
||||
+++
|
||||
** New function 'seq-split'.
|
||||
*** New function 'seq-split'.
|
||||
This returns a list of sub-sequences of the specified sequence.
|
||||
|
||||
+++
|
||||
** New function 'seq-remove-at-position'.
|
||||
*** New function 'seq-remove-at-position'.
|
||||
This function returns a copy of the specified sequence where the
|
||||
element at a given (zero-based) index got removed.
|
||||
|
||||
+++
|
||||
** New function 'seq-positions'.
|
||||
*** New function 'seq-positions'.
|
||||
This returns a list of the (zero-based) indices of elements matching a
|
||||
given predicate in the specified sequence.
|
||||
|
||||
+++
|
||||
** New function 'seq-keep'.
|
||||
*** New function 'seq-keep'.
|
||||
This is like 'seq-map', but removes all nil results from the returned
|
||||
list.
|
||||
|
||||
|
@ -4108,7 +4113,7 @@ where 'major-mode' is 'shell-mode' or a combined with a condition like
|
|||
|
||||
+++
|
||||
** New function 'match-buffers'.
|
||||
Use 'buffer-match-p' to gather a list of buffers that match a
|
||||
It uses 'buffer-match-p' to gather a list of buffers that match a
|
||||
condition.
|
||||
|
||||
---
|
||||
|
|
|
@ -24,7 +24,7 @@ the time being. It will be removed in the next release.
|
|||
|
||||
See https://orgmode.org/list/87r0yk7bx8.fsf@localhost for more details.
|
||||
|
||||
*** Element cache is enabled by default and work for headings
|
||||
*** Element cache is enabled by default and works for headings
|
||||
|
||||
The old element cache code has been refactored. Emacs does not hang
|
||||
anymore when the cache is enabled.
|
||||
|
|
|
@ -21,11 +21,11 @@ Files: catchup.pbm catchup.xpm cu-exit.pbm cu-exit.xpm
|
|||
unsubscribe.pbm unsubscribe.xpm uu-decode.pbm uu-decode.xpm
|
||||
uu-post.pbm uu-post.xpm
|
||||
Author: Luis Fernandes <elf@ee.ryerson.ca>
|
||||
Copyright (C) 2001-2022 Free Software Foundation, Inc.
|
||||
Copyright (C) 2001-2023 Free Software Foundation, Inc.
|
||||
|
||||
Files: gnus.png, gnus.svg
|
||||
Author: Francesc Rocher <rocher@member.fsf.org>
|
||||
Copyright (C) 2008-2022 Free Software Foundation, Inc.
|
||||
Copyright (C) 2008-2023 Free Software Foundation, Inc.
|
||||
|
||||
|
||||
* The following icons are from GNOME 2.x. They are not part of Emacs,
|
||||
|
|
|
@ -14,7 +14,7 @@ Files: hicolor/16x16/apps/emacs23.png hicolor/24x24/apps/emacs23.png
|
|||
hicolor/128x128/apps/emacs23.png hicolor/scalable/apps/emacs23.svg
|
||||
|
||||
Author: Kentaro Ohkouchi <nanasess@fsm.ne.jp>
|
||||
Copyright (C) 2007-2022 Free Software Foundation, Inc.
|
||||
Copyright (C) 2007-2023 Free Software Foundation, Inc.
|
||||
License: GNU General Public License version 3 or later (see COPYING)
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ Files: hicolor/16x16/apps/emacs22.png hicolor/24x24/apps/emacs22.png
|
|||
hicolor/32x32/apps/emacs22.png hicolor/48x48/apps/emacs22.png
|
||||
|
||||
Author: Andrew Zhilin <andrew_zhilin@yahoo.com>
|
||||
Copyright (C) 2005-2022 Free Software Foundation, Inc.
|
||||
Copyright (C) 2005-2023 Free Software Foundation, Inc.
|
||||
License: GNU General Public License version 3 or later (see COPYING)
|
||||
|
||||
Files: allout-widgets-dark-bg/closed.png
|
||||
|
@ -71,5 +71,5 @@ Files: allout-widgets-dark-bg/closed.png
|
|||
allout-widgets-light-bg/through-descender.xpm
|
||||
|
||||
Author: Ken Manheimer <ken.manheimer@gmail.com>
|
||||
Copyright (C) 2011-2022 Free Software Foundation, Inc.
|
||||
Copyright (C) 2011-2023 Free Software Foundation, Inc.
|
||||
License: GNU General Public License version 3 or later (see COPYING)
|
||||
|
|
|
@ -2461,13 +2461,18 @@ INFO may provide the values of these header arguments (in the
|
|||
(insert
|
||||
(org-trim
|
||||
(org-list-to-org
|
||||
;; We arbitrarily choose to format non-strings
|
||||
;; as %S.
|
||||
(cons 'unordered
|
||||
(mapcar
|
||||
(lambda (e)
|
||||
(cond
|
||||
((stringp e) (list e))
|
||||
((listp e)
|
||||
(mapcar (lambda (x) (format "%S" x)) e))
|
||||
(mapcar
|
||||
(lambda (x)
|
||||
(if (stringp x) x (format "%S" x)))
|
||||
e))
|
||||
(t (list (format "%S" e)))))
|
||||
(if (listp result) result
|
||||
(split-string result "\n" t))))
|
||||
|
|
|
@ -3477,14 +3477,14 @@ This ensures the export commands can easily use it."
|
|||
(setq props (plist-put props 'tags (mapconcat #'identity tmp ":"))))
|
||||
(when (setq tmp (plist-get props 'date))
|
||||
(when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
|
||||
(let ((calendar-date-display-form '(year "-" month "-" day)))
|
||||
'((format "%4d, %9s %2s, %4s" dayname monthname day year))
|
||||
|
||||
(let ((calendar-date-display-form
|
||||
'(year "-" (string-pad month 2 ?0 'left) "-" (string-pad day 2 ?0 'left))))
|
||||
(setq tmp (calendar-date-string tmp)))
|
||||
(setq props (plist-put props 'date tmp)))
|
||||
(when (setq tmp (plist-get props 'day))
|
||||
(when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
|
||||
(let ((calendar-date-display-form '(year "-" month "-" day)))
|
||||
(let ((calendar-date-display-form
|
||||
'(year "-" (string-pad month 2 ?0 'left) "-" (string-pad day 2 ?0 'left))))
|
||||
(setq tmp (calendar-date-string tmp)))
|
||||
(setq props (plist-put props 'day tmp))
|
||||
(setq props (plist-put props 'agenda-day tmp)))
|
||||
|
@ -4678,7 +4678,7 @@ is active."
|
|||
(org-agenda-text-search-extra-files org-agenda-text-search-extra-files)
|
||||
regexp rtn rtnall files file pos inherited-tags
|
||||
marker category level tags c neg re boolean
|
||||
ee txt beg end words regexps+ regexps- hdl-only buffer beg1 str)
|
||||
ee txt beg end last-search-end words regexps+ regexps- hdl-only buffer beg1 str)
|
||||
(unless (and (not edit-at)
|
||||
(stringp string)
|
||||
(string-match "\\S-" string))
|
||||
|
@ -4817,6 +4817,7 @@ is active."
|
|||
(throw 'nextfile t))
|
||||
(goto-char (max (point-min) (1- (point))))
|
||||
(while (re-search-forward regexp nil t)
|
||||
(setq last-search-end (point))
|
||||
(org-back-to-heading t)
|
||||
(while (and (not (zerop org-agenda-search-view-max-outline-level))
|
||||
(> (org-reduced-level (org-outline-level))
|
||||
|
@ -4878,7 +4879,7 @@ is active."
|
|||
'priority 1000
|
||||
'type "search")
|
||||
(push txt ee)
|
||||
(goto-char (1- end))))))))))
|
||||
(goto-char (max (1- end) last-search-end))))))))))
|
||||
(setq rtn (nreverse ee))
|
||||
(setq rtnall (append rtnall rtn)))
|
||||
(org-agenda--insert-overriding-header
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
;;; org-cycle.el --- Visibility cycling of Org entries -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; Copyright (C) 2020, 2023-2020 Free Software Foundation, Inc.
|
||||
;; Copyright (C) 2020-2023 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Maintainer: Ihor Radchenko <yantar92 at gmail dot com>
|
||||
;; Keywords: folding, visibility cycling, invisible text
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
;;; org-fold-core.el --- Folding buffer text -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; Copyright (C) 2020, 2023-2020 Free Software Foundation, Inc.
|
||||
;; Copyright (C) 2020-2023 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Author: Ihor Radchenko <yantar92 at gmail dot com>
|
||||
;; Keywords: folding, invisible text
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
;;; org-fold.el --- Folding of Org entries -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; Copyright (C) 2020, 2023-2020 Free Software Foundation, Inc.
|
||||
;; Copyright (C) 2020-2023 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Author: Ihor Radchenko <yantar92 at gmail dot com>
|
||||
;; Keywords: folding, invisible text
|
||||
|
|
|
@ -74,11 +74,15 @@ Version mismatch is commonly encountered in the following situations:
|
|||
loading of the newer Org version.
|
||||
|
||||
It is recommended to put
|
||||
(straight-use-package 'org)
|
||||
|
||||
%s
|
||||
|
||||
early in the config. Ideally, right after the straight.el
|
||||
bootstrap. Moving `use-package' :straight declaration may not be
|
||||
sufficient if the corresponding `use-package' statement is
|
||||
deferring the loading.")
|
||||
deferring the loading."
|
||||
;; Avoid `warn' replacing "'" with "’" (see `format-message').
|
||||
"(straight-use-package 'org)")
|
||||
(error "Org version mismatch. Make sure that correct `load-path' is set early in init.el")))
|
||||
|
||||
;; We rely on org-macs when generating Org version. Checking Org
|
||||
|
|
|
@ -161,7 +161,7 @@
|
|||
(declare-function org-at-heading-p "org" (&optional invisible-not-ok))
|
||||
|
||||
|
||||
(defconst org-persist--storage-version "2.7"
|
||||
(defconst org-persist--storage-version "3.1"
|
||||
"Persistent storage layout version.")
|
||||
|
||||
(defgroup org-persist nil
|
||||
|
@ -431,25 +431,27 @@ Return PLIST."
|
|||
(when key (remhash (cons cont (list :key key)) org-persist--index-hash))))
|
||||
(setq org-persist--index (delq existing org-persist--index)))))
|
||||
|
||||
(defun org-persist--get-collection (container &optional associated &rest misc)
|
||||
(defun org-persist--get-collection (container &optional associated misc)
|
||||
"Return or create collection used to store CONTAINER for ASSOCIATED.
|
||||
When ASSOCIATED is nil, it is a global CONTAINER.
|
||||
ASSOCIATED can also be a (:buffer buffer) or buffer, (:file file-path)
|
||||
or file-path, (:inode inode), (:hash hash), or or (:key key).
|
||||
MISC, if non-nil will be appended to the collection."
|
||||
MISC, if non-nil will be appended to the collection. It must be a plist."
|
||||
(unless (and (listp container) (listp (car container)))
|
||||
(setq container (list container)))
|
||||
(setq associated (org-persist--normalize-associated associated))
|
||||
(unless (equal misc '(nil))
|
||||
(setq associated (append associated misc)))
|
||||
(when (and misc (or (not (listp misc)) (= 1 (% (length misc) 2))))
|
||||
(error "org-persist: Not a plist: %S" misc))
|
||||
(or (org-persist--find-index
|
||||
`( :container ,(org-persist--normalize-container container)
|
||||
:associated ,associated))
|
||||
(org-persist--add-to-index
|
||||
(list :container (org-persist--normalize-container container)
|
||||
:persist-file
|
||||
(replace-regexp-in-string "^.." "\\&/" (org-id-uuid))
|
||||
:associated associated))))
|
||||
(nconc
|
||||
(list :container (org-persist--normalize-container container)
|
||||
:persist-file
|
||||
(replace-regexp-in-string "^.." "\\&/" (org-id-uuid))
|
||||
:associated associated)
|
||||
misc))))
|
||||
|
||||
;;;; Reading container data.
|
||||
|
||||
|
@ -650,9 +652,10 @@ COLLECTION is the plist holding data collection."
|
|||
(file-copy (org-file-name-concat
|
||||
org-persist-directory
|
||||
(format "%s-%s.%s" persist-file (md5 path) ext))))
|
||||
(unless (file-exists-p (file-name-directory file-copy))
|
||||
(make-directory (file-name-directory file-copy) t))
|
||||
(copy-file path file-copy 'overwrite)
|
||||
(unless (file-exists-p file-copy)
|
||||
(unless (file-exists-p (file-name-directory file-copy))
|
||||
(make-directory (file-name-directory file-copy) t))
|
||||
(copy-file path file-copy 'overwrite))
|
||||
(format "%s-%s.%s" persist-file (md5 path) ext)))))
|
||||
|
||||
(defun org-persist-write:url (c collection)
|
||||
|
@ -719,7 +722,8 @@ last access, or a function accepting a single argument - collection.
|
|||
EXPIRY key has no effect when INHERIT is non-nil.
|
||||
Optional key WRITE-IMMEDIATELY controls whether to save the container
|
||||
data immediately.
|
||||
MISC will be appended to CONTAINER.
|
||||
MISC will be appended to the collection. It must be alternating :KEY
|
||||
VALUE pairs.
|
||||
When WRITE-IMMEDIATELY is non-nil, the return value will be the same
|
||||
with `org-persist-write'."
|
||||
(unless org-persist--index (org-persist--load-index))
|
||||
|
|
|
@ -629,83 +629,83 @@ Leave point in edit buffer."
|
|||
"Fontify code block between START and END using LANG's syntax.
|
||||
This function is called by Emacs' automatic fontification, as long
|
||||
as `org-src-fontify-natively' is non-nil."
|
||||
(let ((lang-mode (org-src-get-lang-mode lang)))
|
||||
(when (fboundp lang-mode)
|
||||
(let ((string (buffer-substring-no-properties start end))
|
||||
(modified (buffer-modified-p))
|
||||
(org-buffer (current-buffer)))
|
||||
(remove-text-properties start end '(face nil))
|
||||
(with-current-buffer
|
||||
(get-buffer-create
|
||||
(format " *org-src-fontification:%s*" lang-mode))
|
||||
(let ((inhibit-modification-hooks nil))
|
||||
(erase-buffer)
|
||||
;; Add string and a final space to ensure property change.
|
||||
(insert string " "))
|
||||
(unless (eq major-mode lang-mode) (funcall lang-mode))
|
||||
(font-lock-ensure)
|
||||
(let ((pos (point-min)) next)
|
||||
(while (setq next (next-property-change pos))
|
||||
;; Handle additional properties from font-lock, so as to
|
||||
;; preserve, e.g., composition.
|
||||
;; FIXME: We copy 'font-lock-face property explicitly because
|
||||
;; `font-lock-mode' is not enabled in the buffers starting from
|
||||
;; space and the remapping between 'font-lock-face and 'face
|
||||
;; text properties may thus not be set. See commit
|
||||
;; 453d634bc.
|
||||
(dolist (prop (append '(font-lock-face face) font-lock-extra-managed-props))
|
||||
(let ((new-prop (get-text-property pos prop)))
|
||||
(when new-prop
|
||||
(if (not (eq prop 'invisible))
|
||||
(put-text-property
|
||||
(+ start (1- pos)) (1- (+ start next)) prop new-prop
|
||||
org-buffer)
|
||||
;; Special case. `invisible' text property may
|
||||
;; clash with Org folding. Do not assign
|
||||
;; `invisible' text property directly. Use
|
||||
;; property alias instead.
|
||||
(let ((invisibility-spec
|
||||
(or
|
||||
;; ATOM spec.
|
||||
(and (memq new-prop buffer-invisibility-spec)
|
||||
new-prop)
|
||||
;; (ATOM . ELLIPSIS) spec.
|
||||
(assq new-prop buffer-invisibility-spec))))
|
||||
(with-current-buffer org-buffer
|
||||
;; Add new property alias.
|
||||
(unless (memq 'org-src-invisible
|
||||
(cdr (assq 'invisible char-property-alias-alist)))
|
||||
(setq-local
|
||||
char-property-alias-alist
|
||||
(cons (cons 'invisible
|
||||
(nconc (cdr (assq 'invisible char-property-alias-alist))
|
||||
'(org-src-invisible)))
|
||||
(remove (assq 'invisible char-property-alias-alist)
|
||||
char-property-alias-alist))))
|
||||
;; Carry over the invisibility spec, unless
|
||||
;; already present. Note that there might
|
||||
;; be conflicting invisibility specs from
|
||||
;; different major modes. We cannot do much
|
||||
;; about this then.
|
||||
(when invisibility-spec
|
||||
(add-to-invisibility-spec invisibility-spec))
|
||||
(put-text-property
|
||||
(+ start (1- pos)) (1- (+ start next))
|
||||
'org-src-invisible new-prop
|
||||
org-buffer)))))))
|
||||
(setq pos next)))
|
||||
(set-buffer-modified-p nil))
|
||||
;; Add Org faces.
|
||||
(let ((src-face (nth 1 (assoc-string lang org-src-block-faces t))))
|
||||
(when (or (facep src-face) (listp src-face))
|
||||
(font-lock-append-text-property start end 'face src-face))
|
||||
(font-lock-append-text-property start end 'face 'org-block))
|
||||
;; Clear abbreviated link folding.
|
||||
(org-fold-region start end nil 'org-link)
|
||||
(add-text-properties
|
||||
start end
|
||||
'(font-lock-fontified t fontified t font-lock-multiline t))
|
||||
(set-buffer-modified-p modified)))))
|
||||
(let ((modified (buffer-modified-p)))
|
||||
(remove-text-properties start end '(face nil))
|
||||
(let ((lang-mode (org-src-get-lang-mode lang)))
|
||||
(when (fboundp lang-mode)
|
||||
(let ((string (buffer-substring-no-properties start end))
|
||||
(org-buffer (current-buffer)))
|
||||
(with-current-buffer
|
||||
(get-buffer-create
|
||||
(format " *org-src-fontification:%s*" lang-mode))
|
||||
(let ((inhibit-modification-hooks nil))
|
||||
(erase-buffer)
|
||||
;; Add string and a final space to ensure property change.
|
||||
(insert string " "))
|
||||
(unless (eq major-mode lang-mode) (funcall lang-mode))
|
||||
(font-lock-ensure)
|
||||
(let ((pos (point-min)) next)
|
||||
(while (setq next (next-property-change pos))
|
||||
;; Handle additional properties from font-lock, so as to
|
||||
;; preserve, e.g., composition.
|
||||
;; FIXME: We copy 'font-lock-face property explicitly because
|
||||
;; `font-lock-mode' is not enabled in the buffers starting from
|
||||
;; space and the remapping between 'font-lock-face and 'face
|
||||
;; text properties may thus not be set. See commit
|
||||
;; 453d634bc.
|
||||
(dolist (prop (append '(font-lock-face face) font-lock-extra-managed-props))
|
||||
(let ((new-prop (get-text-property pos prop)))
|
||||
(when new-prop
|
||||
(if (not (eq prop 'invisible))
|
||||
(put-text-property
|
||||
(+ start (1- pos)) (1- (+ start next)) prop new-prop
|
||||
org-buffer)
|
||||
;; Special case. `invisible' text property may
|
||||
;; clash with Org folding. Do not assign
|
||||
;; `invisible' text property directly. Use
|
||||
;; property alias instead.
|
||||
(let ((invisibility-spec
|
||||
(or
|
||||
;; ATOM spec.
|
||||
(and (memq new-prop buffer-invisibility-spec)
|
||||
new-prop)
|
||||
;; (ATOM . ELLIPSIS) spec.
|
||||
(assq new-prop buffer-invisibility-spec))))
|
||||
(with-current-buffer org-buffer
|
||||
;; Add new property alias.
|
||||
(unless (memq 'org-src-invisible
|
||||
(cdr (assq 'invisible char-property-alias-alist)))
|
||||
(setq-local
|
||||
char-property-alias-alist
|
||||
(cons (cons 'invisible
|
||||
(nconc (cdr (assq 'invisible char-property-alias-alist))
|
||||
'(org-src-invisible)))
|
||||
(remove (assq 'invisible char-property-alias-alist)
|
||||
char-property-alias-alist))))
|
||||
;; Carry over the invisibility spec, unless
|
||||
;; already present. Note that there might
|
||||
;; be conflicting invisibility specs from
|
||||
;; different major modes. We cannot do much
|
||||
;; about this then.
|
||||
(when invisibility-spec
|
||||
(add-to-invisibility-spec invisibility-spec))
|
||||
(put-text-property
|
||||
(+ start (1- pos)) (1- (+ start next))
|
||||
'org-src-invisible new-prop
|
||||
org-buffer)))))))
|
||||
(setq pos next)))
|
||||
(set-buffer-modified-p nil)))))
|
||||
;; Add Org faces.
|
||||
(let ((src-face (nth 1 (assoc-string lang org-src-block-faces t))))
|
||||
(when (or (facep src-face) (listp src-face))
|
||||
(font-lock-append-text-property start end 'face src-face))
|
||||
(font-lock-append-text-property start end 'face 'org-block))
|
||||
;; Clear abbreviated link folding.
|
||||
(org-fold-region start end nil 'org-link)
|
||||
(add-text-properties
|
||||
start end
|
||||
'(font-lock-fontified t fontified t font-lock-multiline t))
|
||||
(set-buffer-modified-p modified)))
|
||||
|
||||
(defun org-fontify-inline-src-blocks (limit)
|
||||
"Try to apply `org-fontify-inline-src-blocks-1'."
|
||||
|
|
|
@ -11,7 +11,7 @@ Inserted by installing Org mode or when a release is made."
|
|||
(defun org-git-version ()
|
||||
"The Git version of Org mode.
|
||||
Inserted by installing Org or when a release is made."
|
||||
(let ((org-git-version "release_9.6-61-g63e073f"))
|
||||
(let ((org-git-version "release_9.6-81-g563a43"))
|
||||
org-git-version))
|
||||
|
||||
(provide 'org-version)
|
||||
|
|
|
@ -425,7 +425,7 @@ MODE is either `c' or `cpp'."
|
|||
;; Recurse.
|
||||
((or "attributed_declarator" "parenthesized_declarator")
|
||||
(c-ts-mode--declarator-identifier (treesit-node-child node 0 t)))
|
||||
("pointer_declarator"
|
||||
((or "pointer_declarator" "reference_declarator")
|
||||
(c-ts-mode--declarator-identifier (treesit-node-child node -1)))
|
||||
((or "function_declarator" "array_declarator" "init_declarator")
|
||||
(c-ts-mode--declarator-identifier
|
||||
|
|
|
@ -696,7 +696,7 @@ compilation and evaluation time conflicts."
|
|||
:feature 'expression
|
||||
'((conditional_expression (identifier) @font-lock-variable-name-face)
|
||||
(postfix_unary_expression (identifier)* @font-lock-variable-name-face)
|
||||
(assignment_expression (identifier) @font-lock-variable-name-face))
|
||||
(initializer_expression (assignment_expression left: (identifier) @font-lock-variable-name-face)))
|
||||
|
||||
:language 'c-sharp
|
||||
:feature 'bracket
|
||||
|
@ -764,8 +764,12 @@ compilation and evaluation time conflicts."
|
|||
(identifier) @font-lock-type-face)
|
||||
(type_argument_list
|
||||
(identifier) @font-lock-type-face)
|
||||
(generic_name
|
||||
(identifier) @font-lock-type-face)
|
||||
(type_argument_list
|
||||
(generic_name
|
||||
(identifier) @font-lock-type-face))
|
||||
(base_list
|
||||
(generic_name
|
||||
(identifier) @font-lock-type-face))
|
||||
(array_type
|
||||
(identifier) @font-lock-type-face)
|
||||
(cast_expression (identifier) @font-lock-type-face)
|
||||
|
@ -773,7 +777,12 @@ compilation and evaluation time conflicts."
|
|||
(type_parameter_constraints_clause
|
||||
target: (identifier) @font-lock-type-face)
|
||||
(type_of_expression (identifier) @font-lock-type-face)
|
||||
(object_creation_expression (identifier) @font-lock-type-face))
|
||||
(object_creation_expression
|
||||
type: (identifier) @font-lock-type-face)
|
||||
(object_creation_expression
|
||||
type: (generic_name (identifier) @font-lock-type-face))
|
||||
(as_expression right: (identifier) @font-lock-type-face)
|
||||
(as_expression right: (generic_name (identifier) @font-lock-type-face)))
|
||||
|
||||
:language 'c-sharp
|
||||
:feature 'definition
|
||||
|
@ -793,7 +802,6 @@ compilation and evaluation time conflicts."
|
|||
(record_declaration (identifier) @font-lock-type-face)
|
||||
(namespace_declaration (identifier) @font-lock-type-face)
|
||||
(base_list (identifier) @font-lock-type-face)
|
||||
(property_declaration (generic_name))
|
||||
(property_declaration
|
||||
type: (nullable_type) @font-lock-type-face
|
||||
name: (identifier) @font-lock-variable-name-face)
|
||||
|
@ -807,29 +815,10 @@ compilation and evaluation time conflicts."
|
|||
|
||||
(constructor_declaration name: (_) @font-lock-type-face)
|
||||
|
||||
(method_declaration type: (_) @font-lock-type-face)
|
||||
(method_declaration type: [(identifier) (void_keyword)] @font-lock-type-face)
|
||||
(method_declaration type: (generic_name (identifier) @font-lock-type-face))
|
||||
(method_declaration name: (_) @font-lock-function-name-face)
|
||||
|
||||
(invocation_expression
|
||||
(member_access_expression
|
||||
(generic_name (identifier) @font-lock-function-name-face)))
|
||||
(invocation_expression
|
||||
(member_access_expression
|
||||
((identifier) @font-lock-variable-name-face
|
||||
(identifier) @font-lock-function-name-face)))
|
||||
(invocation_expression
|
||||
(identifier) @font-lock-function-name-face)
|
||||
(invocation_expression
|
||||
(member_access_expression
|
||||
expression: (identifier) @font-lock-variable-name-face))
|
||||
(invocation_expression
|
||||
function: [(generic_name (identifier)) @font-lock-function-name-face
|
||||
(generic_name (type_argument_list
|
||||
["<"] @font-lock-bracket-face
|
||||
(identifier) @font-lock-type-face
|
||||
[">"] @font-lock-bracket-face)
|
||||
)])
|
||||
|
||||
(catch_declaration
|
||||
((identifier) @font-lock-type-face))
|
||||
(catch_declaration
|
||||
|
@ -837,13 +826,30 @@ compilation and evaluation time conflicts."
|
|||
(identifier) @font-lock-variable-name-face))
|
||||
|
||||
(variable_declaration (identifier) @font-lock-type-face)
|
||||
(variable_declaration (generic_name (identifier) @font-lock-type-face))
|
||||
(variable_declarator (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(parameter type: (identifier) @font-lock-type-face)
|
||||
(parameter type: (generic_name (identifier) @font-lock-type-face))
|
||||
(parameter name: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(binary_expression (identifier) @font-lock-variable-name-face)
|
||||
(argument (identifier) @font-lock-variable-name-face))
|
||||
(lambda_expression (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(declaration_expression type: (identifier) @font-lock-type-face)
|
||||
(declaration_expression name: (identifier) @font-lock-variable-name-face))
|
||||
|
||||
:language 'c-sharp
|
||||
:feature 'function
|
||||
'((invocation_expression
|
||||
function: (member_access_expression
|
||||
name: (identifier) @font-lock-function-name-face))
|
||||
(invocation_expression
|
||||
function: (identifier) @font-lock-function-name-face)
|
||||
(invocation_expression
|
||||
function: (member_access_expression
|
||||
name: (generic_name (identifier) @font-lock-function-name-face)))
|
||||
(invocation_expression
|
||||
function: (generic_name (identifier) @font-lock-function-name-face)))
|
||||
|
||||
:language 'c-sharp
|
||||
:feature 'escape-sequence
|
||||
|
@ -921,7 +927,7 @@ Key bindings:
|
|||
'(( comment definition)
|
||||
( keyword string type)
|
||||
( constant escape-sequence expression literal property)
|
||||
( bracket delimiter error)))
|
||||
( function bracket delimiter error)))
|
||||
|
||||
;; Imenu.
|
||||
(setq-local treesit-simple-imenu-settings
|
||||
|
|
|
@ -205,7 +205,7 @@ chosen (interactively or automatically)."
|
|||
(((caml-mode :language-id "ocaml")
|
||||
(tuareg-mode :language-id "ocaml") reason-mode)
|
||||
. ("ocamllsp"))
|
||||
(ruby-mode
|
||||
((ruby-mode ruby-ts-mode)
|
||||
. ("solargraph" "socket" "--port" :autoport))
|
||||
(haskell-mode
|
||||
. ("haskell-language-server-wrapper" "--lsp"))
|
||||
|
|
944
lisp/progmodes/ruby-ts-mode.el
Normal file
944
lisp/progmodes/ruby-ts-mode.el
Normal file
|
@ -0,0 +1,944 @@
|
|||
;;; ruby-ts-mode.el --- Major mode for editing Ruby files using tree-sitter -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2022-2023 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Perry Smith <pedz@easesoftware.com>
|
||||
;; Created: December 2022
|
||||
;; Keywords: ruby languages tree-sitter
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file defines ruby-ts-mode which is a major mode for editting
|
||||
;; Ruby files that uses Tree Sitter to parse the language. More
|
||||
;; information about Tree Sitter can be found in the ELisp Info pages
|
||||
;; as well as this website: https://tree-sitter.github.io/tree-sitter/
|
||||
|
||||
;; For this major mode to work, Emacs has to be compiled with
|
||||
;; tree-sitter support, and the Ruby grammar has to be compiled and
|
||||
;; put somewhere Emacs can find it. See the docstring of
|
||||
;; `treesit-extra-load-path'.
|
||||
|
||||
;; This mode doesn't associate itself with .rb files automatically.
|
||||
;; You can do that either by prepending to the value of
|
||||
;; `auto-mode-alist', or using `major-mode-remap-alist'.
|
||||
|
||||
;; Tree Sitter brings a lot of power and versitility which can be
|
||||
;; broken into these features.
|
||||
|
||||
;; * Font Lock
|
||||
|
||||
;; The ability to color the source code is not new but what is new is
|
||||
;; the versatility to enable and disable particular font lock rules.
|
||||
;; I suggest reviewing variable treesit-font-lock-level and function
|
||||
;; treesit-font-lock-recompute-features to get a better understanding
|
||||
;; of the following.
|
||||
|
||||
;; Currently tree treesit-font-lock-feature-list is set with the
|
||||
;; following levels:
|
||||
;; 1: comment method-definition
|
||||
;; 2: keyword regexp string type
|
||||
;; 3: builtin constant delimiter escape-sequence
|
||||
;; global instance
|
||||
;; interpolation literal symbol variable
|
||||
;; 4: bracket error function operator punctuation
|
||||
|
||||
;; Thus if treesit-font-lock-level is set to level 3 which is its
|
||||
;; default, all the features listed in levels 1 through 3 above will
|
||||
;; be enabled. i.e. those features will font lock or colorize the
|
||||
;; code accordingly. Individual features can be added and removed via
|
||||
;; treesit-font-lock-recompute-features.
|
||||
|
||||
;; describe-face can be used to view how a face looks.
|
||||
|
||||
;; * Indent
|
||||
|
||||
;; ruby-ts-mode tries to adhere to the indentation related user
|
||||
;; options from ruby-mode, such as ruby-indent-level,
|
||||
;; ruby-indent-tabs-mode, and so on.
|
||||
|
||||
;; * IMenu
|
||||
;; * Navigation
|
||||
;; * Which-func
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'treesit)
|
||||
(require 'ruby-mode)
|
||||
|
||||
(declare-function treesit-parser-create "treesit.c")
|
||||
|
||||
(defgroup ruby-ts nil
|
||||
"Major mode for editing Ruby code."
|
||||
:prefix "ruby-ts-"
|
||||
:group 'languages)
|
||||
|
||||
(defcustom ruby-ts-highlight-predefined-constants t
|
||||
"When non-nil, the pre-defined constants are highlighted.
|
||||
They will be highlighted the same way as the pre-defined variables."
|
||||
:type 'boolean)
|
||||
|
||||
(defvar ruby-ts--operators
|
||||
'("+" "-" "*" "/" "%" "**"
|
||||
"==" "!=" ">" "<" ">=" "<=" "<=>" "==="
|
||||
"=" "+=" "-=" "*=" "/=" "%=" "**="
|
||||
"&" "|" "^" "~" "<<" ">>"
|
||||
"!" "&&" "and" "not" "or" "||"
|
||||
"?" ":"
|
||||
".." "..."
|
||||
"defined?"
|
||||
"." "::")
|
||||
"Ruby operators for tree-sitter font-locking.")
|
||||
|
||||
(defvar ruby-ts--delimiters '("," ";")
|
||||
"Ruby's punctuation characters.")
|
||||
|
||||
(defvar ruby-ts--predefined-constants
|
||||
(rx (or "ARGF" "ARGV" "DATA" "ENV" "RUBY_COPYRIGHT"
|
||||
"RUBY_DESCRIPTION" "RUBY_ENGINE" "RUBY_ENGINE_VERSION"
|
||||
"RUBY_PATCHLEVEL" "RUBY_PLATFORM" "RUBY_RELEASE_DATE"
|
||||
"RUBY_REVISION" "RUBY_VERSION" "STDERR" "STDIN" "STDOUT"
|
||||
"TOPLEVEL_BINDING"))
|
||||
"Ruby predefined global constants.
|
||||
These are currently unused")
|
||||
|
||||
(defvar ruby-ts--predefined-variables
|
||||
(rx (or "$!" "$@" "$~" "$&" "$‘" "$‘" "$+" "$=" "$/" "$\\" "$," "$;"
|
||||
"$." "$<" "$>" "$_" "$*" "$$" "$?" "$:" "$LOAD_PATH"
|
||||
"$LOADED_FEATURES" "$DEBUG" "$FILENAME" "$stderr" "$stdin"
|
||||
"$stdout" "$VERBOSE" "$-a" "$-i" "$-l" "$-p"
|
||||
(seq "$" (+ digit))))
|
||||
"Ruby global variables (but not global constants.")
|
||||
|
||||
(defconst ruby-ts--class-or-module-regex
|
||||
(rx string-start
|
||||
(or "class" "module" "singleton_class")
|
||||
string-end)
|
||||
"Regular expression that matches a class or module's node type.")
|
||||
|
||||
(defconst ruby-ts--method-regex
|
||||
(rx string-start
|
||||
(or "method" "singleton_method")
|
||||
string-end)
|
||||
"Regular expression matching methods and singleton methods.")
|
||||
|
||||
(defconst ruby-ts--statement-container-regexp
|
||||
(rx string-start
|
||||
(or "program"
|
||||
"block_body"
|
||||
"begin_block"
|
||||
"end_block"
|
||||
"do"
|
||||
"else"
|
||||
"then"
|
||||
"ensure"
|
||||
"body_statement"
|
||||
"parenthesized_statements"
|
||||
"interpolation")
|
||||
string-end)
|
||||
"Regular expression of the nodes that can constain statements.")
|
||||
|
||||
(defun ruby-ts--lineno (node)
|
||||
"Return line number of NODE's start."
|
||||
(line-number-at-pos (treesit-node-start node)))
|
||||
|
||||
;; doc/keywords.rdoc in the Ruby git repository considers these to be
|
||||
;; reserved keywords. If these keywords are added to the list, it
|
||||
;; causes the font-lock to stop working.
|
||||
;;
|
||||
;; "__ENCODING__" "__FILE__" "__LINE__" "false" "self" "super" "true"
|
||||
;;
|
||||
;; "nil" (which does not exhibit this issue) is also considered a
|
||||
;; keyword but I removed it and added it as a constant.
|
||||
;;
|
||||
(defvar ruby-ts--keywords
|
||||
'("BEGIN" "END" "alias" "and" "begin" "break" "case" "class"
|
||||
"def" "defined?" "do" "else" "elsif" "end" "ensure" "for"
|
||||
"if" "in" "module" "next" "not" "or" "redo" "rescue"
|
||||
"retry" "return" "then" "undef" "unless" "until" "when"
|
||||
"while" "yield")
|
||||
"Ruby keywords for tree-sitter font-locking.")
|
||||
|
||||
(defun ruby-ts--comment-font-lock (node override start end &rest _)
|
||||
"Apply font lock to comment NODE within START and END.
|
||||
Applies `font-lock-comment-delimiter-face' and
|
||||
`font-lock-comment-face' See `treesit-fontify-with-override' for
|
||||
values of OVERRIDE"
|
||||
;; Emperically it appears as if (treesit-node-start node) will be
|
||||
;; where the # character is at and (treesit-node-end node) will be
|
||||
;; the end of the line
|
||||
(let* ((node-start (treesit-node-start node))
|
||||
(plus-1 (1+ node-start))
|
||||
(node-end (treesit-node-end node))
|
||||
(text (treesit-node-text node t)))
|
||||
(if (and (>= node-start start)
|
||||
(<= plus-1 end)
|
||||
(string-match-p "\\`#" text))
|
||||
(treesit-fontify-with-override node-start plus-1
|
||||
font-lock-comment-delimiter-face override))
|
||||
(treesit-fontify-with-override (max plus-1 start) (min node-end end)
|
||||
font-lock-comment-face override)))
|
||||
|
||||
(defun ruby-ts--font-lock-settings (language)
|
||||
"Tree-sitter font-lock settings for Ruby."
|
||||
(treesit-font-lock-rules
|
||||
:language language
|
||||
:feature 'comment
|
||||
'((comment) @ruby-ts--comment-font-lock)
|
||||
|
||||
:language language
|
||||
:feature 'builtin
|
||||
`(((global_variable) @var (:match ,ruby-ts--predefined-variables @var)) @font-lock-builtin-face
|
||||
,@(when ruby-ts-highlight-predefined-constants
|
||||
`(((constant) @var (:match ,ruby-ts--predefined-constants @var)) @font-lock-builtin-face)))
|
||||
|
||||
:language language
|
||||
:feature 'keyword
|
||||
`([,@ruby-ts--keywords] @font-lock-keyword-face)
|
||||
|
||||
:language language
|
||||
:feature 'constant
|
||||
'((true) @font-lock-doc-markup-face
|
||||
(false) @font-lock-doc-markup-face
|
||||
(nil) @font-lock-doc-markup-face
|
||||
(self) @font-lock-doc-markup-face
|
||||
(super) @font-lock-doc-markup-face)
|
||||
|
||||
:language language
|
||||
:feature 'symbol
|
||||
'((bare_symbol) @font-lock-constant-face
|
||||
(delimited_symbol (string_content) @font-lock-constant-face)
|
||||
(hash_key_symbol) @font-lock-constant-face
|
||||
(simple_symbol) @font-lock-constant-face)
|
||||
|
||||
;; Before 'operator so (unary) works.
|
||||
:language language
|
||||
:feature 'literal
|
||||
'((unary ["+" "-"] [(integer) (rational) (float) (complex)]) @font-lock-number-face
|
||||
(integer) @font-lock-number-face
|
||||
(float) @font-lock-number-face
|
||||
(complex) @font-lock-number-face
|
||||
(rational) @font-lock-number-face)
|
||||
|
||||
;; Also before 'operator because % and / are operators
|
||||
:language language
|
||||
:feature 'regexp
|
||||
'((regex "/" @font-lock-regexp-grouping-construct)
|
||||
(regex _ (string_content) @font-lock-regexp-grouping-backslash))
|
||||
|
||||
:language language
|
||||
:feature 'operator
|
||||
`("!" @font-lock-negation-char-face
|
||||
[,@ruby-ts--operators] @font-lock-operator-face)
|
||||
|
||||
;; TODO: Consider using a different face for string delimiters.
|
||||
;; font-lock-delimiter-face is not a good choice, though, because it
|
||||
;; looks like 'default' in the default theme, and its documented purpose
|
||||
;; is characters like commas, semicolons, etc.
|
||||
:language language
|
||||
:feature 'string
|
||||
'((delimited_symbol [ ":\"" "\"" ] @font-lock-string-face)
|
||||
(string "\"" @font-lock-string-face)
|
||||
(string_array [ "%w(" ")" ] @font-lock-delimiter-face)
|
||||
(subshell "`" @font-lock-delimiter-face)
|
||||
(symbol_array [ "%i(" ")"] @font-lock-delimiter-face))
|
||||
|
||||
:language language
|
||||
:feature 'string
|
||||
'((string_content) @font-lock-string-face
|
||||
(heredoc_beginning) @font-lock-string-face
|
||||
(heredoc_content) @font-lock-string-face
|
||||
(heredoc_end) @font-lock-string-face)
|
||||
|
||||
:language language
|
||||
:feature 'interpolation
|
||||
'((interpolation "#{" @font-lock-doc-face)
|
||||
(interpolation "}" @font-lock-doc-face))
|
||||
|
||||
:language language
|
||||
:feature 'type
|
||||
'((constant) @font-lock-type-face)
|
||||
|
||||
:language language
|
||||
:feature 'global
|
||||
'((global_variable) @font-lock-variable-name-face)
|
||||
|
||||
:language language
|
||||
:feature 'instance
|
||||
'((instance_variable) @font-lock-variable-name-face)
|
||||
|
||||
:language language
|
||||
:feature 'method-definition
|
||||
'((method
|
||||
name: (identifier) @font-lock-function-name-face)
|
||||
(singleton_method
|
||||
name: (identifier) @font-lock-function-name-face)
|
||||
(method
|
||||
name: (setter) @font-lock-function-name-face))
|
||||
|
||||
;; Yuan recommends also putting method definitions into the
|
||||
;; 'function' category (thus keeping it in both). I've opted to
|
||||
;; just use separate categories for them -- dgutov.
|
||||
:language language
|
||||
:feature 'function
|
||||
'((call
|
||||
method: (identifier) @font-lock-function-name-face))
|
||||
|
||||
:language language
|
||||
:feature 'error
|
||||
'((ERROR) @font-lock-warning-face)
|
||||
|
||||
:feature 'escape-sequence
|
||||
:language language
|
||||
:override t
|
||||
'((escape_sequence) @font-lock-escape-face)
|
||||
|
||||
:language language
|
||||
:feature 'bracket
|
||||
'((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face)
|
||||
|
||||
:language language
|
||||
:feature 'punctuation
|
||||
`(([,@ruby-ts--delimiters] @font-lock-delimiter-face))))
|
||||
|
||||
(defun ruby-ts--first-non-comment-child (node)
|
||||
"Return the first named child of NODE that is not a comment."
|
||||
(let ((child (treesit-node-child node 0 t)))
|
||||
(while (and child
|
||||
(equal "comment" (treesit-node-type child)))
|
||||
(setq child (treesit-node-next-sibling child t)))
|
||||
child))
|
||||
|
||||
;;
|
||||
;; These routines would be better added to treesit.el They are
|
||||
;; intended to be used with indent rules
|
||||
;;
|
||||
;; I think this is over simplified but basically
|
||||
;; treesit--simple-indent-eval calls the result with node, parent, and
|
||||
;; bol. Thus all of these functions return a lambda that accepts three
|
||||
;; arguments. Somewhere something explains that &rest should always
|
||||
;; be used in case extra arguments are added in the future.
|
||||
;;
|
||||
|
||||
(defun ruby-ts--type-pred (regexp)
|
||||
"Return predicate taking a node returning non-nil if REGEXP matches type of node."
|
||||
(lambda (node)
|
||||
(string-match-p regexp (treesit-node-type node))))
|
||||
|
||||
(defun ruby-ts--parent-node (_n parent &rest _)
|
||||
"Return the PARENT node matching ident rule."
|
||||
parent)
|
||||
|
||||
(defun ruby-ts--align-keywords (pred)
|
||||
"Return either start or bol of PRED.
|
||||
PRED should specify a node that is listed in
|
||||
`ruby-alignable-keywords'. If PRED is listed in user option
|
||||
`ruby-align-to-stmt-keywords', then return the BOL of PRED.
|
||||
Otherwise return start of PRED."
|
||||
(lambda (node parent bol &rest rest)
|
||||
(let* ((pred-node (funcall pred node parent bol rest))
|
||||
(temp (treesit-node-start pred-node))
|
||||
(keyword (treesit-node-type pred-node))
|
||||
(bol (ruby-smie--indent-to-stmt-p keyword)))
|
||||
(when temp
|
||||
(if bol
|
||||
(save-excursion
|
||||
(goto-char temp)
|
||||
(back-to-indentation)
|
||||
(point))
|
||||
temp)))))
|
||||
|
||||
(defun ruby-ts--bol (pred)
|
||||
"Return bol of PRED.
|
||||
PRED should take (node parent bol &rest rest) and return a node.
|
||||
Returns bol of the current line if PRED returns nil."
|
||||
(lambda (node parent bol &rest rest)
|
||||
(save-excursion
|
||||
(let ((temp (treesit-node-start (funcall pred node parent bol rest))))
|
||||
(if temp
|
||||
(goto-char temp))
|
||||
(back-to-indentation)
|
||||
(point)))))
|
||||
|
||||
(defun ruby-ts--grand-parent-node (_n parent &rest _)
|
||||
"Return parent of PARENT node."
|
||||
(treesit-node-parent parent))
|
||||
|
||||
(defun ruby-ts--align-chain-p (&rest _)
|
||||
"Return value of `ruby-align-chained-calls'."
|
||||
ruby-align-chained-calls)
|
||||
|
||||
(defun ruby-ts--parenless-call-arguments-indent-p (&rest _)
|
||||
"Return value of `ruby-parenless-call-arguments-indent'."
|
||||
ruby-parenless-call-arguments-indent)
|
||||
|
||||
(defun ruby-ts--align-chain (_n parent &rest _)
|
||||
"Align chained method call.
|
||||
Align NODE which will be the dot (.) to the dot of the
|
||||
first (outermost) call in the chain. See
|
||||
`ruby-align-chained-calls' for details. PARENT will be the
|
||||
\"call\" node. Called only when `ruby-align-chained-calls' is
|
||||
non-nil."
|
||||
(let* (first-call )
|
||||
(while (and parent
|
||||
(setq first-call (treesit-node-parent parent))
|
||||
(string-match-p "call" (treesit-node-type first-call)))
|
||||
(setq parent first-call))
|
||||
(treesit-node-start (treesit-search-subtree parent "\\." nil t))))
|
||||
|
||||
(defun ruby-ts--same-line-args-p (_n parent &rest _)
|
||||
"Return non-nil when first argument is on the same line as the method.
|
||||
PARENT will be argument_list. NODE can be the close paren."
|
||||
(let* ((method (treesit-node-parent parent))
|
||||
(first-param (ruby-ts--first-non-comment-child parent)))
|
||||
(= (ruby-ts--lineno method) (ruby-ts--lineno first-param))))
|
||||
|
||||
(defun ruby-ts--same-line-params-p (_n parent &rest _)
|
||||
"Return non-nil when first parameter is on the same line as the method.
|
||||
PARENT will be method_parameters. NODE can be the close paren."
|
||||
(let* ((method (treesit-node-parent parent))
|
||||
(first-param (ruby-ts--first-non-comment-child parent)))
|
||||
(= (ruby-ts--lineno method) (ruby-ts--lineno first-param))))
|
||||
|
||||
(defun ruby-ts--param-indent (_n parent &rest _)
|
||||
"Indent parameters that start on next line.
|
||||
Given: NODE is the parameter. PARENT is
|
||||
method_parameters. `ruby-ts--same-line-params-p' is nil.
|
||||
Indent according to `ruby-method-params-indent'.
|
||||
|
||||
If `ruby-method-params-indent' is 0
|
||||
def foo(
|
||||
param1,
|
||||
param2
|
||||
)
|
||||
|
||||
Params start on next line, `ruby-method-params-indent' is t
|
||||
def foo(
|
||||
param1,
|
||||
param2
|
||||
)"
|
||||
(let ((method (treesit-node-parent parent)))
|
||||
(if (eq t ruby-method-params-indent)
|
||||
;; For methods, the "name" is the name of the method but for
|
||||
;; singleton methods, we need to find "object"
|
||||
(let* ((singleton (equal "singleton_method" (treesit-node-type method)))
|
||||
(name-node (treesit-node-child-by-field-name
|
||||
method
|
||||
(if singleton "object" "name"))))
|
||||
;; (message "name-node: %S" name-node)
|
||||
(treesit-node-start name-node))
|
||||
;; Small Danger: if the method name plus the parent is less than
|
||||
;; `ruby-method-params-indent', then the addition will put the
|
||||
;; result on the next line and indented incorrectly. There are
|
||||
;; plausible ways to fix this but the probability seems rather
|
||||
;; remote.
|
||||
(+ (treesit-node-start method) (or ruby-method-params-indent 0)))))
|
||||
|
||||
(defun ruby-ts--true (&rest _)
|
||||
"I have no idea why I can't just put t but I can put 0."
|
||||
t)
|
||||
|
||||
(defun ruby-ts--same-line-hash-array-p (_n parent &rest _)
|
||||
"Return non-nil if first element and open brace are on the same line.
|
||||
NODE is the element or closing brace or bracket. PARENT is the
|
||||
array or hash."
|
||||
(let* ((open-brace (treesit-node-child parent 0 nil))
|
||||
(first-child (ruby-ts--first-non-comment-child parent)))
|
||||
(= (ruby-ts--lineno open-brace) (ruby-ts--lineno first-child))))
|
||||
|
||||
(defun ruby-ts--assignment-ancestor (node &rest _)
|
||||
"Return the assignment ancestor of NODE if any."
|
||||
(treesit-parent-until node (ruby-ts--type-pred "\\`assignment\\'")))
|
||||
|
||||
(defun ruby-ts--statement-ancestor (node &rest _)
|
||||
"Return the statement ancestor of NODE if any.
|
||||
A statement is defined as a child of a statement container where
|
||||
a statement container is a node that matches
|
||||
`ruby-ts--statement-container-regexp'."
|
||||
(let* ((statement node)
|
||||
(parent (treesit-node-parent statement)))
|
||||
(while (and parent
|
||||
statement
|
||||
(not (string-match-p ruby-ts--statement-container-regexp
|
||||
(treesit-node-type parent))))
|
||||
(setq statement parent
|
||||
parent (treesit-node-parent parent)))
|
||||
statement))
|
||||
|
||||
(defun ruby-ts--is-in-condition (node &rest _)
|
||||
"Return the condition node if NODE is within a condition."
|
||||
(while (and node
|
||||
(not (equal "condition" (treesit-node-field-name node)))
|
||||
(not (string-match-p ruby-ts--statement-container-regexp
|
||||
(treesit-node-type node))))
|
||||
(setq node (treesit-node-parent node)))
|
||||
(and (equal "condition" (treesit-node-field-name node)) node))
|
||||
|
||||
(defun ruby-ts--endless-method (node &rest _)
|
||||
"Return the expression node if NODE is in an endless method.
|
||||
i.e. expr of def foo(args) = expr is returned."
|
||||
(let* ((method node))
|
||||
(while (and method
|
||||
(not (string-match-p ruby-ts--method-regex (treesit-node-type method))))
|
||||
(setq method (treesit-node-parent method)))
|
||||
(when method
|
||||
(if (equal "=" (treesit-node-type (treesit-node-child method 3 nil)))
|
||||
(treesit-node-child method 4 nil)))))
|
||||
|
||||
;;
|
||||
;; end of functions that can be used for queries
|
||||
;;
|
||||
|
||||
(defun ruby-ts--indent-rules ()
|
||||
"Indent rules supported by `ruby-ts-mode'."
|
||||
(let ((common
|
||||
`(
|
||||
;; Slam all top level nodes to the left margin
|
||||
((parent-is "program") parent 0)
|
||||
|
||||
;; Do not indent here docs or the end. Not sure why it
|
||||
;; takes the grand-parent but ok fine.
|
||||
((n-p-gp nil nil "heredoc_body") no-indent 0)
|
||||
((parent-is "heredoc_body") no-indent 0)
|
||||
((node-is "heredoc_body") no-indent 0)
|
||||
;; Do not indent multiline regexp
|
||||
((n-p-gp nil nil "regex") no-indent 0)
|
||||
((parent-is "regex") no-indent 0)
|
||||
|
||||
;; if then else elseif notes:
|
||||
;;
|
||||
;; 1. The "then" starts at the end of the line that ends
|
||||
;; the if condition which can be on a different line
|
||||
;; from the "if".
|
||||
;;
|
||||
;; 2. If there is an "elsif", it is a sibling to the then
|
||||
;; BUT the "else" that follows is now a child of the
|
||||
;; "elsif".
|
||||
;;
|
||||
;; 3. The statements within each of these are direct
|
||||
;; children. There is no intermediate construct such
|
||||
;; as a block_statement.
|
||||
;;
|
||||
;; I'm using very restrictive patterns hoping to reduce rules
|
||||
;; triggering unintentionally.
|
||||
((match "else" "if")
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
|
||||
((match "elsif" "if")
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
|
||||
((match "end" "if")
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
|
||||
((n-p-gp nil "then\\|else\\|elsif" "if\\|unless")
|
||||
(ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
|
||||
;; case expression: when, in_clause, and else are all
|
||||
;; children of case. when and in_clause have pattern and
|
||||
;; body as fields. body has "then" and then the statemets.
|
||||
;; i.e. the statements are not children of when but then.
|
||||
;; But for the statements are children of else.
|
||||
((match "when" "case")
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
|
||||
((match "in_clause" "case")
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
|
||||
((match "else" "case")
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
|
||||
((match "end" "case")
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
|
||||
((n-p-gp nil "then" "when") grand-parent ruby-indent-level)
|
||||
((n-p-gp nil "then" "in_clause") grand-parent ruby-indent-level)
|
||||
((n-p-gp nil "else" "case") parent ruby-indent-level)
|
||||
|
||||
;; The beauty of inconsistency :-)
|
||||
;; while / until have only "do" as a child. The "end" is a
|
||||
;; child of "do".
|
||||
((n-p-gp "end" "do" "while\\|until")
|
||||
(ruby-ts--align-keywords ruby-ts--grand-parent-node) 0)
|
||||
((n-p-gp nil "do" "while\\|until")
|
||||
(ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
;; begin can have rescue, ensure, else, and end.
|
||||
;; statements are a child of begin. rescue, ensure, else,
|
||||
;; and end are also children of begin. rescue has a then
|
||||
;; as a child thus statements will be grand children of
|
||||
;; rescue.
|
||||
((n-p-gp nil "then" "rescue")
|
||||
(ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
((n-p-gp nil "ensure\\|else" "begin")
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) ruby-indent-level)
|
||||
((match "rescue\\|ensure\\|else\\|end" "begin")
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
|
||||
((parent-is "begin") ;last
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) ruby-indent-level)
|
||||
|
||||
;; for ... I don't think I have ever used a for loop in
|
||||
;; Ruby. The "in" (not an in_clause) and "do" are
|
||||
;; children. The statements are children of the "do".
|
||||
;; And, of course, the "end" is a child of the "do".
|
||||
((n-p-gp "end" "do" "for")
|
||||
(ruby-ts--align-keywords ruby-ts--grand-parent-node) 0)
|
||||
((n-p-gp nil "do" "for")
|
||||
(ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
|
||||
;; method has a "body_statement" and the "end" as children.
|
||||
;; The body_statement can have rescue, ensure, and else as
|
||||
;; well as statements. Note that the first statement of a
|
||||
;; body_statement hits the node as "body_statement" and not
|
||||
;; as the assignment, etc.
|
||||
((match "end" ,ruby-ts--method-regex)
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
|
||||
((n-p-gp "\\`\\(rescue\\|ensure\\|else\\)\\'" "body_statement" ,ruby-ts--method-regex)
|
||||
(ruby-ts--align-keywords ruby-ts--grand-parent-node) 0)
|
||||
((n-p-gp nil "rescue\\|ensure\\|else" "body_statement") parent ruby-indent-level)
|
||||
((match "body_statement" ,ruby-ts--method-regex) ;first statement
|
||||
(ruby-ts--align-keywords ruby-ts--parent-node) ruby-indent-level)
|
||||
((n-p-gp nil "body_statement" ,ruby-ts--method-regex) ;other statements
|
||||
(ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
|
||||
;; Chained calls:
|
||||
;; if `ruby-align-chained-calls' is true, the first query
|
||||
;; matches and the node is aligned under the first dot (.);
|
||||
;; else the second query aligns
|
||||
;; `ruby-indent-level' spaces in from the parent.
|
||||
((and ruby-ts--align-chain-p (match "\\." "call")) ruby-ts--align-chain 0)
|
||||
((match "\\." "call") parent ruby-indent-level)
|
||||
|
||||
;; ruby-indent-after-block-in-continued-expression
|
||||
((match "begin" "assignment") parent ruby-indent-level)
|
||||
|
||||
;; method parameters -- four styles:
|
||||
;; 1) With paren, first arg on same line:
|
||||
((and (query "(method_parameters \"(\" _ @indent)")
|
||||
ruby-ts--same-line-params-p
|
||||
(node-is ")"))
|
||||
first-sibling 0)
|
||||
((and (query "(method_parameters \"(\" _ @indent)")
|
||||
ruby-ts--same-line-params-p)
|
||||
first-sibling 1)
|
||||
;; ;; 2) With paren, first arg on next line, ruby-method-params-indent eq t
|
||||
;; ;; 3) With paren, first arg on next line, ruby-method-params-indent neq t
|
||||
((and (query "(method_parameters \"(\" _ @indent)") (node-is ")")) ruby-ts--param-indent 0)
|
||||
((query "(method_parameters \"(\" _ @indent)") ruby-ts--param-indent ruby-indent-level)
|
||||
;; 4) No paren:
|
||||
((parent-is "method_parameters") first-sibling 0)
|
||||
|
||||
;; Argument lists:
|
||||
;; 1) With paren, 1st arg on same line
|
||||
((and (query "(argument_list \"(\" _ @indent)")
|
||||
ruby-ts--same-line-args-p
|
||||
(node-is ")"))
|
||||
first-sibling 0)
|
||||
((and (query "(argument_list \"(\" _ @indent)")
|
||||
ruby-ts--same-line-args-p)
|
||||
first-sibling 1)
|
||||
;; 2) With paren, 1st arg on next line
|
||||
((and (query "(argument_list \"(\" _ @indent)")
|
||||
(node-is ")"))
|
||||
(ruby-ts--bol ruby-ts--grand-parent-node) 0)
|
||||
((query "(argument_list \"(\" _ @indent)")
|
||||
(ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
;; 3) No paren, ruby-parenless-call-arguments-indent is t
|
||||
((and ruby-ts--parenless-call-arguments-indent-p (parent-is "argument_list"))
|
||||
first-sibling 0)
|
||||
;; 4) No paren, ruby-parenless-call-arguments-indent is nil
|
||||
((parent-is "argument_list") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
|
||||
;; Old... probably too simple
|
||||
((parent-is "block_parameters") first-sibling 1)
|
||||
|
||||
((and (parent-is "binary")
|
||||
(or ruby-ts--assignment-ancestor
|
||||
ruby-ts--is-in-condition
|
||||
ruby-ts--endless-method))
|
||||
first-sibling 0)
|
||||
|
||||
;; ruby-mode does not touch these...
|
||||
((match "bare_string" "string_array") no-indent 0)
|
||||
|
||||
;; hash and array other than assignments. Note that the
|
||||
;; first sibling is the "{" or "[". There is a special
|
||||
;; case where the hash is an argument to a method. These
|
||||
;; need to be processed first.
|
||||
|
||||
((and ruby-ts--same-line-hash-array-p (match "}" "hash"))
|
||||
first-sibling 0)
|
||||
((and ruby-ts--same-line-hash-array-p (parent-is "hash"))
|
||||
(nth-sibling 0 ruby-ts--true) 0)
|
||||
((and ruby-ts--same-line-hash-array-p (match "]" "array"))
|
||||
first-sibling 0)
|
||||
((and ruby-ts--same-line-hash-array-p (parent-is "array"))
|
||||
(nth-sibling 0 ruby-ts--true) 0)
|
||||
|
||||
;; NOTE to folks trying to understand my insanity...
|
||||
;; I having trouble understanding the "logic" of why things
|
||||
;; are indented like they are so I am adding special cases
|
||||
;; hoping at some point I will be struck by lightning.
|
||||
((and (n-p-gp "}" "hash" "pair")
|
||||
(not ruby-ts--same-line-hash-array-p))
|
||||
grand-parent 0)
|
||||
((and (n-p-gp "pair" "hash" "pair")
|
||||
(not ruby-ts--same-line-hash-array-p))
|
||||
grand-parent ruby-indent-level)
|
||||
((and (n-p-gp "}" "hash" "method")
|
||||
(not ruby-ts--same-line-hash-array-p))
|
||||
grand-parent 0)
|
||||
((and (n-p-gp "pair" "hash" "method")
|
||||
(not ruby-ts--same-line-hash-array-p))
|
||||
grand-parent ruby-indent-level)
|
||||
|
||||
((n-p-gp "}" "hash" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) 0)
|
||||
((n-p-gp nil "hash" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
((n-p-gp "]" "array" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) 0)
|
||||
((n-p-gp nil "array" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
|
||||
((n-p-gp "}" "hash" "argument_list") first-sibling 0)
|
||||
((n-p-gp nil "hash" "argument_list") first-sibling ruby-indent-level)
|
||||
((n-p-gp "]" "array" "argument_list") first-sibling 0)
|
||||
((n-p-gp nil "array" "argument_list") first-sibling ruby-indent-level)
|
||||
|
||||
((match "}" "hash") first-sibling 0)
|
||||
((parent-is "hash") first-sibling ruby-indent-level)
|
||||
((match "]" "array") first-sibling 0)
|
||||
((parent-is "array") first-sibling ruby-indent-level)
|
||||
|
||||
;; If the previous method isn't finished yet, this will get
|
||||
;; the next method indented properly.
|
||||
((n-p-gp ,ruby-ts--method-regex "body_statement" ,ruby-ts--class-or-module-regex)
|
||||
(ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
|
||||
;; Match the end of a class / modlue
|
||||
((match "end" ,ruby-ts--class-or-module-regex) parent 0)
|
||||
|
||||
;; A "do_block" has a "body_statement" child which has the
|
||||
;; statements as children within it. The problem is that
|
||||
;; the first statement starts at the same point as the
|
||||
;; body_statement and so treesit-simple-indent is called
|
||||
;; with node set to body_statement on the first statement
|
||||
;; but with node set to the statement and parent set to
|
||||
;; body_statement for all others. ... Fine. Be that way.
|
||||
;; Ditto for "block" and "block_body"
|
||||
((node-is "body_statement") parent-bol ruby-indent-level)
|
||||
((parent-is "body_statement") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
((match "end" "do_block") parent-bol 0)
|
||||
((n-p-gp "block_body" "block" nil) parent-bol ruby-indent-level)
|
||||
((n-p-gp nil "block_body" "block") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
|
||||
((match "}" "block") (ruby-ts--bol ruby-ts--grand-parent-node) 0)
|
||||
|
||||
;; Chained strings
|
||||
((match "string" "chained_string") first-sibling 0)
|
||||
|
||||
;; Try and indent two spaces when all else fails.
|
||||
(catch-all parent-bol ruby-indent-level))))
|
||||
`((ruby . ,common))))
|
||||
|
||||
(defun ruby-ts--class-or-module-p (node)
|
||||
"Predicate if NODE is a class or module."
|
||||
(string-match-p ruby-ts--class-or-module-regex (treesit-node-type node)))
|
||||
|
||||
(defun ruby-ts--get-name (node)
|
||||
"Return the text of the `name' field of NODE."
|
||||
(treesit-node-text (treesit-node-child-by-field-name node "name")))
|
||||
|
||||
(defun ruby-ts--full-name (node)
|
||||
"Return the fully qualified name of NODE."
|
||||
(let* ((name (ruby-ts--get-name node))
|
||||
(delimiter "#"))
|
||||
(while (setq node (treesit-parent-until node #'ruby-ts--class-or-module-p))
|
||||
(setq name (concat (ruby-ts--get-name node) delimiter name))
|
||||
(setq delimiter "::"))
|
||||
name))
|
||||
|
||||
(defun ruby-ts--imenu-helper (node)
|
||||
"Convert a treesit sparse tree NODE in an imenu list.
|
||||
Helper for `ruby-ts--imenu' which converts a treesit sparse
|
||||
NODE into a list of imenu ( name . pos ) nodes"
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'ruby-ts--imenu-helper (cdr node)))
|
||||
(name (when ts-node
|
||||
(ruby-ts--full-name ts-node)))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
(cond
|
||||
((or (null ts-node) (null name)) subtrees)
|
||||
;; Don't include the anonymous "class" and "module" nodes
|
||||
((string-match-p "(\"\\(class\\|module\\)\")"
|
||||
(treesit-node-string ts-node))
|
||||
nil)
|
||||
(subtrees
|
||||
`((,name ,(cons name marker) ,@subtrees)))
|
||||
(t
|
||||
`((,name . ,marker))))))
|
||||
|
||||
;; For now, this is going to work like ruby-mode and return a list of
|
||||
;; class, modules, def (methods), and alias. It is likely that this
|
||||
;; can be rigged to be easily extended.
|
||||
(defun ruby-ts--imenu ()
|
||||
"Return Imenu alist for the current buffer."
|
||||
(let* ((root (treesit-buffer-root-node))
|
||||
(nodes (treesit-induce-sparse-tree root "^\\(method\\|alias\\|class\\|module\\)$")))
|
||||
(ruby-ts--imenu-helper nodes)))
|
||||
|
||||
(defun ruby-ts--arrow-up-start (arg)
|
||||
"Move to the start ARG levels up or out."
|
||||
(interactive "p")
|
||||
(setq arg (or arg 1))
|
||||
(let* ((pnt (point))
|
||||
(found (treesit-node-at pnt))
|
||||
(pos (treesit-node-start found))
|
||||
new-pos)
|
||||
(while (and found pos (> arg 0))
|
||||
(setq found (treesit-node-parent found)
|
||||
new-pos (treesit-node-start found))
|
||||
(when (and new-pos (not (= new-pos pos)))
|
||||
(setq arg (1- arg)
|
||||
pos new-pos)))
|
||||
(if pos
|
||||
(goto-char pos)
|
||||
(error "Something didn't work"))))
|
||||
|
||||
(defun ruby-ts--class-name (node)
|
||||
"Return NODE's name.
|
||||
Assumes NODE's type is \"class\" or \"method\""
|
||||
(list
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name
|
||||
node
|
||||
(if (equal "singleton_class" (treesit-node-type node)) "value" "name"))
|
||||
t)))
|
||||
|
||||
(defun ruby-ts--method-name (node)
|
||||
"Return the method name of NODE.
|
||||
Assumes NODE's type is method or singleton_method."
|
||||
(if (equal "method" (treesit-node-type node))
|
||||
(list (treesit-node-text (treesit-node-child-by-field-name node "name") t))
|
||||
(let* ((children (treesit-node-children node))
|
||||
;; 0th is "def"
|
||||
(first (nth 1 children))
|
||||
(third (nth 3 children)))
|
||||
(cond
|
||||
((equal "(" (treesit-node-type first))
|
||||
(list (treesit-node-text (nth 2 children) t)
|
||||
(treesit-node-text (nth 5 children) t)))
|
||||
;; ((equal "self" (treesit-node-type first))
|
||||
;; (list (treesit-node-text third t)))
|
||||
(t (mapcar (lambda (n)
|
||||
(treesit-node-text n t))
|
||||
(list first third)))))))
|
||||
|
||||
(defun ruby-ts-add-log-current-function ()
|
||||
"Return the current method name as a string.
|
||||
The hash (#) is for instance methods only which are methods
|
||||
\"defined on a class\" -- which is 99% of methods. Otherwise, a
|
||||
dot (.) is used. Double colon (::) is used between classes. The
|
||||
leading double colon is not added."
|
||||
(let* ((node (treesit-node-at (point)))
|
||||
(method (treesit-parent-until node (ruby-ts--type-pred ruby-ts--method-regex)))
|
||||
(class (or method node))
|
||||
(result nil)
|
||||
(sep "#")
|
||||
(method-list nil)
|
||||
(class-list nil)
|
||||
(method-name nil))
|
||||
|
||||
(when method
|
||||
(setq method-list (ruby-ts--method-name method))
|
||||
(unless (= 1 (length method-list))
|
||||
(setq sep ".")))
|
||||
(while (setq class (treesit-parent-until class
|
||||
(ruby-ts--type-pred
|
||||
ruby-ts--class-or-module-regex)))
|
||||
(setq class-list (append (ruby-ts--class-name class) class-list)))
|
||||
(setq method-name (car (last method-list))
|
||||
method-list (butlast method-list))
|
||||
(when (equal (car method-list) (car (last class-list)))
|
||||
(setq method-list (cdr method-list)))
|
||||
(dolist (ele (append class-list method-list))
|
||||
(cond
|
||||
((equal "self" ele)
|
||||
(setq sep "."))
|
||||
((string-match-p "\\`[^A-Z]" ele) ;not a class
|
||||
(setq sep "."
|
||||
result (if result
|
||||
(concat result "::" ele)
|
||||
ele)))
|
||||
(t (setq result (if result
|
||||
(concat result "::" ele)
|
||||
ele)))))
|
||||
(if method-name
|
||||
(concat result sep method-name)
|
||||
result)))
|
||||
|
||||
(defvar-keymap ruby-ts-mode-map
|
||||
:doc "Keymap used in Ruby mode"
|
||||
:parent prog-mode-map
|
||||
;; (when ruby-use-smie
|
||||
;; (define-key map (kbd "M-C-d") 'smie-down-list))
|
||||
;; (define-key map (kbd "M-C-p") 'ruby-beginning-of-block)
|
||||
;; (define-key map (kbd "M-C-n") 'ruby-end-of-block)
|
||||
"C-c {" #'ruby-toggle-block
|
||||
"C-c '" #'ruby-toggle-string-quotes
|
||||
"C-c C-f" #'ruby-find-library-file)
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode ruby-ts-mode prog-mode "Ruby"
|
||||
"Major mode for editing Ruby, powered by tree-sitter."
|
||||
:group 'ruby
|
||||
:syntax-table ruby-mode-syntax-table
|
||||
|
||||
(setq indent-tabs-mode ruby-indent-tabs-mode)
|
||||
|
||||
(setq-local paragraph-start (concat "$\\|" page-delimiter))
|
||||
(setq-local paragraph-separate paragraph-start)
|
||||
(setq-local paragraph-ignore-fill-prefix t)
|
||||
|
||||
(setq-local comment-start "# ")
|
||||
(setq-local comment-end "")
|
||||
(setq-local comment-start-skip "#+ *")
|
||||
|
||||
(unless (treesit-ready-p 'ruby)
|
||||
(error "Tree-sitter for Ruby isn't available"))
|
||||
|
||||
(treesit-parser-create 'ruby)
|
||||
|
||||
(setq-local add-log-current-defun-function #'ruby-ts-add-log-current-function)
|
||||
|
||||
;; Navigation.
|
||||
(setq-local treesit-defun-type-regexp ruby-ts--method-regex)
|
||||
|
||||
;; AFAIK, Ruby can not nest methods
|
||||
(setq-local treesit-defun-prefer-top-level nil)
|
||||
|
||||
;; Imenu.
|
||||
(setq-local imenu-create-index-function #'ruby-ts--imenu)
|
||||
|
||||
(setq-local treesit-simple-indent-rules (ruby-ts--indent-rules))
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings (ruby-ts--font-lock-settings 'ruby))
|
||||
;; Level 3 is the default.
|
||||
(setq-local treesit-font-lock-feature-list
|
||||
'(( comment method-definition )
|
||||
( keyword regexp string type)
|
||||
( builtin constant
|
||||
delimiter escape-sequence global
|
||||
instance
|
||||
interpolation literal symbol variable)
|
||||
( bracket error function operator punctuation)))
|
||||
|
||||
(treesit-major-mode-setup))
|
||||
|
||||
(provide 'ruby-ts-mode)
|
||||
|
||||
;;; ruby-ts-mode.el ends here
|
|
@ -3590,7 +3590,7 @@ Return what remains of the list."
|
|||
;; said it would do.
|
||||
(unless (and (= start start-mark)
|
||||
(= (+ delta end) end-mark))
|
||||
(error "Changes to be undone by function different from announced"))
|
||||
(error "Changes undone by function are different from the announced ones"))
|
||||
(set-marker start-mark nil)
|
||||
(set-marker end-mark nil))
|
||||
(apply fun-args))
|
||||
|
|
|
@ -2810,6 +2810,8 @@ function signals an error."
|
|||
(rx bos (+ anychar) ".o" eos))
|
||||
"-o" ,lib-name))
|
||||
;; Copy out.
|
||||
(unless (file-exists-p out-dir)
|
||||
(make-directory out-dir t))
|
||||
(copy-file lib-name (file-name-as-directory out-dir) t t)
|
||||
(message "Library installed to %s/%s" out-dir lib-name))
|
||||
(when (file-exists-p workdir)
|
||||
|
|
|
@ -59,7 +59,8 @@
|
|||
"\nCopyright 2006, 2007, 2008 Foo Bar\n\n")
|
||||
(copyright-update)
|
||||
(buffer-substring (- (point-max) 42) (point-max))))
|
||||
"Copyright 2006, 2007, 2008, 2022 Foo Bar\n\n")))
|
||||
(format "Copyright 2006, 2007, 2008, %s Foo Bar\n\n"
|
||||
(format-time-string "%Y")))))
|
||||
|
||||
(ert-deftest test-correct-notice ()
|
||||
(should (equal
|
||||
|
@ -70,7 +71,8 @@
|
|||
(copyright-query nil))
|
||||
(copyright-update))
|
||||
(buffer-string))
|
||||
"Copyright 2021 FSF\nCopyright 2021, 2022 FSF\n")))
|
||||
(format "Copyright 2021 FSF\nCopyright 2021, %s FSF\n"
|
||||
(format-time-string "%Y")))))
|
||||
|
||||
(defmacro with-copyright-fix-years-test (orig result)
|
||||
`(let ((copyright-year-ranges t))
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
(require 'ert)
|
||||
(require 'shortdoc)
|
||||
(require 'subr-x) ; `string-pad' in shortdoc group needed at run time
|
||||
(require 'regexp-opt) ; `regexp-opt-charset' not autoloaded
|
||||
|
||||
(defun shortdoc-tests--tree-contains (tree fun)
|
||||
"Whether TREE contains a call to FUN."
|
||||
|
|
254
test/lisp/progmodes/ruby-ts-mode-tests.el
Normal file
254
test/lisp/progmodes/ruby-ts-mode-tests.el
Normal file
|
@ -0,0 +1,254 @@
|
|||
;;; ruby-mode-tests.el --- Test suite for ruby-mode -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'ert)
|
||||
(require 'ert-x)
|
||||
(require 'ruby-ts-mode)
|
||||
|
||||
(defmacro ruby-ts-with-temp-buffer (contents &rest body)
|
||||
(declare (indent 1) (debug t))
|
||||
`(with-temp-buffer
|
||||
(insert ,contents)
|
||||
(ruby-ts-mode)
|
||||
,@body))
|
||||
|
||||
(defun ruby-ts-should-indent-buffer (expected content)
|
||||
"Assert that CONTENT turns into EXPECTED after the buffer is re-indented.
|
||||
|
||||
The whitespace before and including \"|\" on each line is removed."
|
||||
(ruby-ts-with-temp-buffer (ruby-ts-test-string content)
|
||||
(indent-region (point-min) (point-max))
|
||||
(should (string= (ruby-ts-test-string expected) (buffer-string)))))
|
||||
|
||||
(defun ruby-ts-test-string (s &rest args)
|
||||
(apply 'format (replace-regexp-in-string "^[ \t]*|" "" s) args))
|
||||
|
||||
(ert-deftest ruby-ts-indent-simple ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(ruby-ts-should-indent-buffer
|
||||
"if foo
|
||||
| bar
|
||||
|end
|
||||
|zot
|
||||
|"
|
||||
"if foo
|
||||
|bar
|
||||
| end
|
||||
| zot
|
||||
|"))
|
||||
|
||||
(ert-deftest ruby-ts-align-to-stmt-keywords-t ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(let ((ruby-align-to-stmt-keywords t))
|
||||
(ruby-ts-should-indent-buffer
|
||||
"foo = if bar?
|
||||
| 1
|
||||
|else
|
||||
| 2
|
||||
|end
|
||||
|
|
||||
|foo || begin
|
||||
| bar
|
||||
|end
|
||||
|
|
||||
|foo ||
|
||||
| begin
|
||||
| bar
|
||||
| end
|
||||
|"
|
||||
"foo = if bar?
|
||||
| 1
|
||||
|else
|
||||
| 2
|
||||
| end
|
||||
|
|
||||
| foo || begin
|
||||
| bar
|
||||
|end
|
||||
|
|
||||
| foo ||
|
||||
| begin
|
||||
|bar
|
||||
| end
|
||||
|")
|
||||
))
|
||||
|
||||
(ert-deftest ruby-ts-align-to-stmt-keywords-case ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(let ((ruby-align-to-stmt-keywords '(case)))
|
||||
(ruby-ts-should-indent-buffer
|
||||
"b = case a
|
||||
|when 13
|
||||
| 6
|
||||
|else
|
||||
| 42
|
||||
|end"
|
||||
"b = case a
|
||||
| when 13
|
||||
| 6
|
||||
| else
|
||||
| 42
|
||||
| end")))
|
||||
|
||||
(ert-deftest ruby-ts-add-log-current-method-examples ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(let ((pairs '(("foo" . "#foo")
|
||||
("C.foo" . ".foo")
|
||||
("self.foo" . ".foo")
|
||||
("<<" . "#<<"))))
|
||||
(dolist (pair pairs)
|
||||
(let ((name (car pair))
|
||||
(value (cdr pair)))
|
||||
(ruby-ts-with-temp-buffer (ruby-ts-test-string
|
||||
"module M
|
||||
| class C
|
||||
| def %s
|
||||
| _
|
||||
| end
|
||||
| end
|
||||
|end"
|
||||
name)
|
||||
(search-backward "_")
|
||||
(forward-line)
|
||||
(should (string= (ruby-ts-add-log-current-function)
|
||||
(format "M::C%s" value))))))))
|
||||
|
||||
(ert-deftest ruby-ts-add-log-current-method-outside-of-method ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(ruby-ts-with-temp-buffer (ruby-ts-test-string
|
||||
"module M
|
||||
| class C
|
||||
| def foo
|
||||
| end
|
||||
| _
|
||||
| end
|
||||
|end")
|
||||
(search-backward "_")
|
||||
(should (string= (ruby-ts-add-log-current-function) "M::C"))))
|
||||
|
||||
(ert-deftest ruby-ts-add-log-current-method-in-singleton-class ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(ruby-ts-with-temp-buffer (ruby-ts-test-string
|
||||
"class C
|
||||
| class << self
|
||||
| def foo
|
||||
| _
|
||||
| end
|
||||
| end
|
||||
|end")
|
||||
(search-backward "_")
|
||||
(should (string= (ruby-ts-add-log-current-function) "C.foo"))))
|
||||
|
||||
(ert-deftest ruby-ts-add-log-current-method-namespace-shorthand ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(ruby-ts-with-temp-buffer (ruby-ts-test-string
|
||||
"class C::D
|
||||
| def foo
|
||||
| _
|
||||
| end
|
||||
|end")
|
||||
(search-backward "_")
|
||||
(should (string= (ruby-ts-add-log-current-function) "C::D#foo"))))
|
||||
|
||||
(ert-deftest ruby-ts-add-log-current-method-after-inner-class ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(ruby-ts-with-temp-buffer (ruby-ts-test-string
|
||||
"module M
|
||||
| class C
|
||||
| class D
|
||||
| end
|
||||
| def foo
|
||||
| _
|
||||
| end
|
||||
| end
|
||||
|end")
|
||||
(search-backward "_")
|
||||
(should (string= (ruby-ts-add-log-current-function) "M::C#foo"))))
|
||||
|
||||
(ert-deftest ruby-ts-add-log-current-method-after-inner-class-outside-methods ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(ruby-ts-with-temp-buffer (ruby-ts-test-string
|
||||
"module M
|
||||
| class C
|
||||
| class D
|
||||
| end
|
||||
|
|
||||
|_
|
||||
| end
|
||||
|end")
|
||||
(search-backward "_")
|
||||
(delete-char 1)
|
||||
(should (string= (ruby-ts-add-log-current-function) "M::C"))))
|
||||
|
||||
(ert-deftest ruby-ts-add-log-current-method-after-inner-class-outside-methods-with-text ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(ruby-ts-with-temp-buffer (ruby-ts-test-string
|
||||
"module M
|
||||
| class C
|
||||
| class D
|
||||
| end
|
||||
|
|
||||
| FOO = 5
|
||||
| end
|
||||
|end")
|
||||
(search-backward "FOO")
|
||||
(should (string= (ruby-ts-add-log-current-function) "M::C"))))
|
||||
|
||||
(ert-deftest ruby-ts-add-log-current-method-after-endless-method ()
|
||||
(skip-unless (treesit-available-p))
|
||||
(ruby-ts-with-temp-buffer (ruby-ts-test-string
|
||||
"module M
|
||||
| class C
|
||||
| def foo =
|
||||
| 4_
|
||||
| end
|
||||
|end")
|
||||
(search-backward "_")
|
||||
(delete-char 1)
|
||||
(should (string= (ruby-ts-add-log-current-function) "M::C#foo"))))
|
||||
|
||||
(defmacro ruby-ts-resource-file (file)
|
||||
`(when-let ((testfile ,(or (macroexp-file-name)
|
||||
buffer-file-name)))
|
||||
(let ((default-directory (file-name-directory testfile)))
|
||||
(file-truename
|
||||
(expand-file-name (format "ruby-mode-resources/%s" ,file))))))
|
||||
|
||||
(defmacro ruby-ts-deftest-indent (file)
|
||||
`(ert-deftest ,(intern (format "ruby-ts-indent-test/%s" file)) ()
|
||||
;; :tags '(:expensive-test)
|
||||
(skip-unless (treesit-available-p))
|
||||
(let ((buf (find-file-noselect (ruby-ts-resource-file ,file))))
|
||||
(unwind-protect
|
||||
(with-current-buffer buf
|
||||
(let ((orig (buffer-string)))
|
||||
;; Indent and check that we get the original text.
|
||||
(indent-region (point-min) (point-max))
|
||||
(should (equal (buffer-string) orig))))
|
||||
(kill-buffer buf)))))
|
||||
|
||||
(ruby-ts-deftest-indent "ruby-method-params-indent.rb")
|
||||
|
||||
(provide 'ruby-ts-mode-tests)
|
||||
|
||||
;;; ruby-ts-mode-tests.el ends here
|
Loading…
Add table
Reference in a new issue