Merge from origin/emacs-29

ea87c54f35 ; * lisp/subr.el (setq-local): Add missing period (bug#62...
90362f87d5 ; Correct last commit, downcase node reference
38067f05b9 Enhance section about troubleshooting in Eglot manual.
6f82596b49 Fix Eglot's snippet insertion to follow the manual
c54bda15e3 Reset abbrevs-changed after saving abbrevs (bug#62208)
e8cee15f78 ; Fix markup in previous change
e4a7d0cd6e Document `keymap-unset' in lispref
bb3e0ded9e Don't add a key binding when REMOVE is non-nil
a4a9ffdd80 Fix the documentation of various aspects of adding Xref h...
a2222b9a9b ; Minor wording fix in ELisp reference manual
5cf1de683b Fix python-fill-paragraph problems on filling strings (bu...
7385c991df Also exempt eglot-inlay-hints-mode from desktop.el's fumb...
1961bdb52e ; Add WebDAV entry to index in Tramp manual
dfb36d3623 Refer to EWW instead of w3 and w3m
9d3fdf7e0d Fix Eglot's command generation for code actions

# Conflicts:
#	etc/NEWS
This commit is contained in:
Stefan Kangas 2023-03-20 06:30:32 +01:00
commit 20d8a1cf4b
16 changed files with 345 additions and 101 deletions

View file

@ -2283,16 +2283,25 @@ buffer, but doesn't select any of them.
@kindex M-,
@findex xref-go-back
To go back to places @emph{from where} you've displayed the definition,
use @kbd{M-,} (@code{xref-go-back}). It jumps back to the
To go back to places @emph{from where} you've displayed the
definition, use @kbd{M-,} (@code{xref-go-back}). It jumps back to the
point of the last invocation of @kbd{M-.}. Thus you can find and
examine the definition of something with @kbd{M-.} and then return to
where you were with @kbd{M-,}.
where you were with @kbd{M-,}. @kbd{M-,} allows you to retrace the
steps you made forward in the history of places, all the way to the
first place in history, where you first invoked @kbd{M-.}, or to any
place in-between.
@kindex C-M-,
@findex xref-go-forward
If you previously went back too far with @kbd{M-,}, @kbd{C-M-,}
(@code{xref-go-forward}) can be used to go forward again.
If you previously went back too far with @kbd{M-,}, or want to
re-examine a place from which you went back, you can use @kbd{C-M-,}
(@code{xref-go-forward}) to go forward again. This is similar to
using @kbd{M-.}, except that you don't need on each step to move point
to the identifier whose definition you want to look up. @kbd{C-M-,}
allows you to retrace all the steps you made back in the history of
places, all the way to the last place in history, where you invoked
@kbd{M-,}, or to any place in-between.
@findex xref-etags-mode
Some major modes install @code{xref} support facilities that might

View file

@ -1438,6 +1438,18 @@ If there was previously no binding for @var{key} in @var{keymap}, the
new binding is added at the beginning of @var{keymap}. The order of
bindings in a keymap makes no difference for keyboard input, but it
does matter for menu keymaps (@pxref{Menu Keymaps}).
@end defun
@findex keymap-unset
@defun keymap-unset keymap key &optional remove
This function is the inverse of @code{keymap-set}, it unsets the
binding for @var{key} in @var{keymap}, which is the same as setting
the binding to @code{nil}. In order to instead remove the binding
completely, specify @var{remove} as non-nil. This only makes a
difference if @var{keymap} has a parent keymap. When unsetting a key
in a child map, it will still shadow the same key in the parent
keymap. Removing the binding will allow the key in the parent keymap
to be used.
@end defun
This example creates a sparse keymap and makes a number of

View file

@ -466,19 +466,20 @@ You can specify characters by their Unicode values.
@code{?\u@var{xxxx}} and @code{?\U@var{xxxxxxxx}} represent code
points @var{xxxx} and @var{xxxxxxxx}, respectively, where each @var{x}
is a single hexadecimal digit. For example, @code{?\N@{U+E0@}},
@code{?\u00e0} and @code{?\U000000E0} are all equivalent to @code{?à}
and to @samp{?\N@{LATIN SMALL LETTER A WITH GRAVE@}}. The Unicode
Standard defines code points only up to @samp{U+@var{10ffff}}, so if
you specify a code point higher than that, Emacs signals an error.
@code{?\u00e0} and @code{?\U000000E0} are all equivalent to
@code{?@`a} and to @samp{?\N@{LATIN SMALL LETTER A WITH GRAVE@}}. The
Unicode Standard defines code points only up to @samp{U+@var{10ffff}},
so if you specify a code point higher than that, Emacs signals an
error.
@item
You can specify characters by their hexadecimal character
codes. A hexadecimal escape sequence consists of a backslash,
@samp{x}, and the hexadecimal character code. Thus, @samp{?\x41} is
the character @kbd{A}, @samp{?\x1} is the character @kbd{C-a}, and
@code{?\xe0} is the character @kbd{à} (@kbd{a} with grave accent).
You can use any number of hex digits, so you can represent any
character code in this way.
@code{?\xe0} is the character @kbd{@`a} (@kbd{a} with grave accent).
You can use one or more hex digits after @samp{x}, so you can
represent any character code in this way.
@item
@cindex octal character code

View file

@ -1292,53 +1292,103 @@ pop up special buffers that can be used to inspect the communications
between the Eglot and language server. In many cases, this will
indicate the problems or at least provide a hint.
@cindex performance
A common and easy-to-fix cause of performance problems is the length
of these two buffers. If Eglot is operating correctly but slowly,
customize the variable @code{eglot-events-buffer-size} (@pxref{Eglot
Variables}) to limit logging, and thus speed things up.
of the Eglot events buffer because it represent additional work that
Eglot must do. After verifying Eglot is operating correctly but
slowly, try to customize the variable @code{eglot-events-buffer-size}
(@pxref{Eglot Variables}) to 0. This will disable any debug logging
and may speed things up.
If you need to report an Eglot bug, please keep in mind that, because
there are so many variables involved, it is generally both very
@emph{difficult} and @emph{absolutely essential} to reproduce bugs
exactly as they happened to you, the user. Therefore, every bug
report should include:
In other situations, the cause of poor performance lies in the LSP
server itself. Servers use aggressive caching and other techniques to
improve their performance. Often, this can be tweaked by changing the
server configuration (@pxref{Advanced server configuration}).
If you think you have found a bug, we want to hear about it. Before
reporting a bug, keep in mind that interaction with LSP servers
represents a large quantity of unknown variables. Therefore, it is
generally both @emph{difficult} and @emph{absolutely essential} that
the maintainers reproduce bugs exactly as they happened to you, the
user.
To report an Eglot bug, send e-mail to @email{bug-gnu-emacs@@gnu.org}.
Get acquainted with Emacs's bug reporting guidelines (@pxref{Bugs,,,
emacs, GNU Emacs Manual}). Then, follow this checklist specific to
Eglot bug rerpots.
@enumerate
@item
The transcript of events obtained from the buffer popped up by
@kbd{M-x eglot-events-buffer}. If the transcript can be narrowed down
to show the problematic exchange, so much the better. This is
invaluable for the investigation and reproduction of the problem.
Include the transcript of JSONRPC events obtained from the buffer
popped up by @kbd{M-x eglot-events-buffer}. You may narrow down the
transcript if you are sure of where the problematic exchange is, but
it's safer to include the whole transcript, either attached or inline.
@item
If Emacs signaled an error (an error message was seen or heard), make
sure to repeat the process after toggling @code{debug-on-error} on
(via @kbd{M-x toggle-debug-on-error}). This normally produces a
backtrace of the error that should also be attached to the bug report.
sure to repeat the process after turning on @code{debug-on-error} via
@kbd{M-x toggle-debug-on-error}. This normally produces a backtrace
of the error that should also be attached to the bug report.
@item
An explanation of how to obtain, install, and configure the language
server you used. If possible, try to replicate the problem with the
C/C@t{++} or Python servers, as these are very easy to install.
Include a description of how the maintainer should obtain, install,
and configure the language server you used. Maintainers usually have
access to GNU/Linux systems, though not necessarily the distribution
that you may be using. If possible, try to replicate the problem with
the C/C@t{++} or Python servers, as these are very easy to install.
@item
A description of how to setup the @emph{minimal} project (one or two
files and their contents) where the problem happens.
Describe how to setup a @emph{minimal} project directory where Eglot
should be started for the problem to happen. Describe each file's
name and its contents. Alternatively, you can supply the address of a
public Git repository.
@item
A recipe to replicate the problem with @emph{a clean Emacs run}. This
means @kbd{emacs -Q} invocation or a very minimal (no more that 10
lines) @file{.emacs} initialization file. @code{eglot-ensure} and
@code{use-package} calls are generally @emph{not} needed.
Include versions of the software used. The Emacs version can be
obtained with @kbd{M-x emacs-version}.
It's also essential to include the version of ELPA packages that are
explicitly or implicitly loaded. The optional but popular Company or
Markdown packages are distributed as GNU ELPA packages, not to mention
Eglot itself in some situations. Some major modes (Go, Rust, etc.)
are provided by ELPA packages. It's sometimes easy to miss these,
since they are usually implicitly loaded when visiting a file in that
language.
ELPA packages usually live in @code{~/.emacs.d/elpa} (or what is in
@code{package-user-dir}). Please show the listing of files in that
directory as well.
@item
Make sure to double check all the above elements and re-run the
recipe to see that the problem is reproducible.
Include a recipe to replicate the problem with @emph{a clean Emacs
run}. This means @kbd{emacs -Q -f package-initialize} invocation
which starts Emacs with no configuration and initializes the ELPA
packages. A very minimal (no more that 10 lines) @file{.emacs}
initialization file is also acceptable and good means to describe
changes to variables.
There is usually no need to include @kbd{require} statements in the
recipe, as Eglot's functionality uses autoloads.
Likewise, there is rarely the need to use things like
@code{use-package} or @code{eglot-ensure}. This just makes the recipe
harder to follow. Prefer setting variables with @code{setq} and
adding to hooks with @code{add-hook}. Prefer starting Eglot with
@code{M-x eglot}.
@item
Make sure to double check all the above elements and re-run the recipe
to see that the problem is reproducible. Following the recipe should
produce event transcript and error backtraces that are exactly the
same or very similar to the ones you included. If the problem only
happens sometimes, include this information in your bug report.
@end enumerate
Please keep in mind that some problems reported against Eglot may
actually be bugs in the language server or the Emacs feature/package
that used Eglot to communicate with the language server.
that used Eglot to communicate with the language server. Eglot is, in
many cases, just a frontend to that functionality.
@node GNU Free Documentation License
@appendix GNU Free Documentation License

View file

@ -1372,10 +1372,9 @@ among, with differing advantages and disadvantages. The variable
to (as long as @code{idlwave-help-use-assistant} is not set). This
function is used to set the variable @code{browse-url-browser-function}
locally for IDLWAVE help only. Customize the latter variable to see
what choices of browsers your system offers. Certain browsers like
@code{w3} (bundled with many versions of Emacs) and @code{w3m}
(@uref{http://emacs-w3m.namazu.org/}) are run within Emacs, and use
Emacs buffers to display the HTML help. This can be convenient,
what choices of browsers your system offers. Certain browsers like EWW
(@pxref{Top, EWW,, eww, The Emacs Web Wowser Manual}) are run within Emacs,
and use Emacs buffers to display the HTML help. This can be convenient,
especially on small displays, and images can even be displayed in-line
on newer Emacs versions. However, better formatting results are often
achieved with external browsers, like Mozilla. IDLWAVE assumes any

View file

@ -1247,6 +1247,7 @@ syntax requires a leading volume (share) name, for example:
@item @option{dav}
@item @option{davs}
@cindex WebDAV
@cindex method @option{dav}
@cindex method @option{davs}
@cindex @option{dav} method

View file

@ -2540,8 +2540,16 @@ the project by a VC project based on that VCS.
+++
*** New command 'xref-go-forward'.
It is bound to 'C-M-,' and jumps to the location where 'xref-go-back'
('M-,', also known as 'xref-pop-marker-stack') was invoked previously.
It is bound to 'C-M-,' and jumps to the location where you previously
invoked 'xref-go-back' ('M-,', also known as 'xref-pop-marker-stack').
+++
*** The depth of the Xref marker stack is now infinite.
The implementation of the Xref marker stack was changed in a way that
allows as many places to be saved on the stack as needed, limited only
by the available memory. Therefore, the variables
'find-tag-marker-ring-length' and 'xref-marker-ring-length' are now
obsolete and unused; setting them has no effect.
+++
*** 'xref-query-replace-in-results' prompting change.

View file

@ -1250,17 +1250,17 @@ which see."
;; asked to.
(and save-abbrevs
abbrevs-changed
(progn
(if (or arg
(eq save-abbrevs 'silently)
(y-or-n-p (format "Save abbrevs in %s? " abbrev-file-name)))
(progn
(write-abbrev-file nil)
nil)
;; Don't keep bothering user if they say no.
(setq abbrevs-changed nil)
;; Inhibit message in `save-some-buffers'.
t)))))
(prog1
(if (or arg
(eq save-abbrevs 'silently)
(y-or-n-p (format "Save abbrevs in %s? " abbrev-file-name)))
(progn
(write-abbrev-file nil)
nil)
;; Inhibit message in `save-some-buffers'.
t)
;; Don't ask again whether saved or user said no.
(setq abbrevs-changed nil)))))
(add-hook 'save-some-buffers-functions #'abbrev--possibly-save)

View file

@ -759,7 +759,9 @@ treated as in `eglot--dbind'."
:completion (list :dynamicRegistration :json-false
:completionItem
`(:snippetSupport
,(if (eglot--snippet-expansion-fn)
,(if (and
(not (eglot--stay-out-of-p 'yasnippet))
(eglot--snippet-expansion-fn))
t
:json-false)
:deprecatedSupport t
@ -1627,9 +1629,11 @@ If optional MARKER, return a marker instead"
(defun eglot--snippet-expansion-fn ()
"Compute a function to expand snippets.
Doubles as an indicator of snippet support."
(and (boundp 'yas-minor-mode)
(symbol-value 'yas-minor-mode)
'yas-expand-snippet))
(and (fboundp 'yas-minor-mode)
(lambda (&rest args)
(with-no-warnings
(unless (bound-and-true-p yas-minor-mode) (yas-minor-mode 1))
(apply #'yas-expand-snippet args)))))
(defun eglot--format-markup (markup)
"Format MARKUP according to LSP's spec."
@ -2892,8 +2896,7 @@ for which LSP on-type-formatting should be requested."
;; it'll be adjusted. If no usable
;; insertText at all, label is best,
;; too.
(cond ((or (and (eql insertTextFormat 2)
(eglot--snippet-expansion-fn))
(cond ((or (eql insertTextFormat 2)
textEdit
(null insertText)
(string-empty-p insertText))
@ -3376,7 +3379,7 @@ at point. With prefix argument, prompt for ACTION-KIND."
`(defun ,name (beg &optional end)
,(format "Execute `%s' code actions between BEG and END." kind)
(interactive (eglot--region-bounds))
(eglot-code-actions beg end ,kind)))
(eglot-code-actions beg end ,kind t)))
(eglot--code-action eglot-code-action-organize-imports "source.organizeImports")
(eglot--code-action eglot-code-action-extract "refactor.extract")
@ -3659,13 +3662,11 @@ If NOERROR, return predicate, else erroring function."
;;; Hacks
;;;
;; FIXME: Although desktop.el compatibility is Emacs bug#56407, the
;; optimal solution agreed to there is a bit more work than what I
;; have time to right now. See
;; e.g. https://debbugs.gnu.org/cgi/bugreport.cgi?bug=bug%2356407#68.
;; For now, just use `with-eval-after-load'
;; Emacs bug#56407, the optimal solution is in desktop.el, but that's
;; harder. For now, use `with-eval-after-load'. See also github#1183.
(with-eval-after-load 'desktop
(add-to-list 'desktop-minor-mode-handlers '(eglot--managed-mode . ignore)))
(add-to-list 'desktop-minor-mode-handlers '(eglot--managed-mode . ignore))
(add-to-list 'desktop-minor-mode-handlers '(eglot-inlay-hints-mode . ignore)))
;;; Misc

View file

@ -146,7 +146,10 @@ Otherwise, `find-tag-default' is used."
(define-obsolete-variable-alias 'find-tag-marker-ring-length
'tags-location-ring-length "25.1")
(defvar tags-location-ring-length 16)
(defvar tags-location-ring-length 16
"Size of the find-tag marker ring.
This variable has no effect, and is kept only for backward compatibility.
The actual size of the find-tag marker ring is unlimited.")
(defcustom tags-tag-face 'default
"Face for tags in the output of `tags-apropos'."
@ -181,8 +184,9 @@ Example value:
(sexp :tag "Tags to search")))
:version "21.1")
;; Obsolete variable kept for compatibility. We don't use it in any way.
(defvar find-tag-marker-ring (make-ring 16))
(defvar find-tag-marker-ring (make-ring 16)
"Find-tag marker ring.
Obsolete variable kept for compatibility. It is not used in any way.")
(make-obsolete-variable
'find-tag-marker-ring
"use `xref-push-marker-stack' or `xref-go-back' instead."

View file

@ -511,19 +511,28 @@ This variant of `rx' supports common Python named REGEXPS."
(''string
`(let ((ppss (or ,syntax-ppss (syntax-ppss))))
(and (nth 3 ppss) (nth 8 ppss))))
(''single-quoted-string
`(let ((ppss (or ,syntax-ppss (syntax-ppss))))
(and (characterp (nth 3 ppss)) (nth 8 ppss))))
(''triple-quoted-string
`(let ((ppss (or ,syntax-ppss (syntax-ppss))))
(and (eq t (nth 3 ppss)) (nth 8 ppss))))
(''paren
`(nth 1 (or ,syntax-ppss (syntax-ppss))))
(_ form))))
(defun python-syntax-context (type &optional syntax-ppss)
"Return non-nil if point is on TYPE using SYNTAX-PPSS.
TYPE can be `comment', `string' or `paren'. It returns the start
TYPE can be `comment', `string', `single-quoted-string',
`triple-quoted-string' or `paren'. It returns the start
character address of the specified TYPE."
(declare (compiler-macro python-syntax--context-compiler-macro))
(let ((ppss (or syntax-ppss (syntax-ppss))))
(pcase type
('comment (and (nth 4 ppss) (nth 8 ppss)))
('string (and (nth 3 ppss) (nth 8 ppss)))
('single-quoted-string (and (characterp (nth 3 ppss)) (nth 8 ppss)))
('triple-quoted-string (and (eq t (nth 3 ppss)) (nth 8 ppss)))
('paren (nth 1 ppss))
(_ nil))))
@ -4805,9 +4814,7 @@ Optional argument JUSTIFY defines if the paragraph should be justified."
((python-syntax-context 'comment)
(funcall python-fill-comment-function justify))
;; Strings/Docstrings
((save-excursion (or (python-syntax-context 'string)
(equal (string-to-syntax "|")
(syntax-after (point)))))
((python-info-triple-quoted-string-p)
(funcall python-fill-string-function justify))
;; Decorators
((equal (char-after (save-excursion
@ -4833,10 +4840,7 @@ JUSTIFY should be used (if applicable) as in `fill-paragraph'."
(let* ((str-start-pos
(set-marker
(make-marker)
(or (python-syntax-context 'string)
(and (equal (string-to-syntax "|")
(syntax-after (point)))
(point)))))
(python-info-triple-quoted-string-p)))
;; JT@2021-09-21: Since bug#49518's fix this will always be 1
(num-quotes (python-syntax-count-quotes
(char-after str-start-pos) str-start-pos))
@ -6043,6 +6047,21 @@ point's current `syntax-ppss'."
((python-info-looking-at-beginning-of-defun))
(t nil))))))
(defun python-info-triple-quoted-string-p ()
"Check if point is in a triple quoted string including quotes.
It returns the position of the third quote character of the start
of the string."
(save-excursion
(let ((pos (point)))
(cl-loop
for offset in '(0 3 -2 2 -1 1)
if (let ((check-pos (+ pos offset)))
(and (>= check-pos (point-min))
(<= check-pos (point-max))
(python-syntax-context
'triple-quoted-string (syntax-ppss check-pos))))
return it))))
(defun python-info-encoding-from-cookie ()
"Detect current buffer's encoding from its coding cookie.
Returns the encoding as a symbol."

View file

@ -355,8 +355,10 @@ backward."
(t (goto-char start) nil))))
;; Dummy variable retained for compatibility.
(defvar xref-marker-ring-length 16)
(defvar xref-marker-ring-length 16
"Xref marker ring length.
This is a dummy variable retained for backward compatibility, and
otherwise unused.")
(make-obsolete-variable 'xref-marker-ring-length nil "29.1")
(defcustom xref-prompt-for-identifier '(not xref-find-definitions
@ -453,7 +455,9 @@ are predefined:
(make-obsolete-variable 'xref--marker-ring 'xref--history "29.1")
(defun xref-set-marker-ring-length (_var _val)
(declare (obsolete nil "29.1"))
(declare (obsolete
"this function has no effect: Xref marker ring is now unlimited in size"
"29.1"))
nil)
(defun xref--make-xref-history ()
@ -499,7 +503,7 @@ Override existing value with NEW-VALUE if NEW-VALUE is set."
(defun xref-push-marker-stack (&optional m)
"Add point M (defaults to `point-marker') to the marker stack.
The future stack is erased."
Erase the stack slots following this one."
(xref--push-backward (or m (point-marker)))
(let ((history (xref--get-history)))
(dolist (mk (cdr history))
@ -527,7 +531,7 @@ To undo, use \\[xref-go-forward]."
;;;###autoload
(defun xref-go-forward ()
"Got to the point where a previous \\[xref-go-back] was invoked."
"Go to the point where a previous \\[xref-go-back] was invoked."
(interactive)
(let ((history (xref--get-history)))
(if (null (cdr history))

View file

@ -163,7 +163,7 @@ of previous VARs.
(defmacro setq-local (&rest pairs)
"Make each VARIABLE buffer-local and assign to it the corresponding VALUE.
The arguments are variable/value pairs For each VARIABLE in a pair,
The arguments are variable/value pairs. For each VARIABLE in a pair,
make VARIABLE buffer-local and assign to it the corresponding VALUE
of the pair. The VARIABLEs are literal symbols and should not be quoted.

View file

@ -887,22 +887,23 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx,
keymap_end:
/* We have scanned the entire keymap, and not found a binding for
IDX. Let's add one. */
{
Lisp_Object elt;
if (!remove)
{
Lisp_Object elt;
if (CONSP (idx) && CHARACTERP (XCAR (idx)))
{
/* IDX specifies a range of characters, and not all of them
were handled yet, which means this keymap doesn't have a
char-table. So, we insert a char-table now. */
elt = Fmake_char_table (Qkeymap, Qnil);
Fset_char_table_range (elt, idx, NILP (def) ? Qt : def);
}
else
elt = Fcons (idx, def);
CHECK_IMPURE (insertion_point, XCONS (insertion_point));
XSETCDR (insertion_point, Fcons (elt, XCDR (insertion_point)));
}
if (CONSP (idx) && CHARACTERP (XCAR (idx)))
{
/* IDX specifies a range of characters, and not all of them
were handled yet, which means this keymap doesn't have a
char-table. So, we insert a char-table now. */
elt = Fmake_char_table (Qkeymap, Qnil);
Fset_char_table_range (elt, idx, NILP (def) ? Qt : def);
}
else
elt = Fcons (idx, def);
CHECK_IMPURE (insertion_point, XCONS (insertion_point));
XSETCDR (insertion_point, Fcons (elt, XCDR (insertion_point)));
}
}
return def;

View file

@ -305,6 +305,22 @@
(should-not (abbrev-table-p translation-table-vector))
(should (abbrev-table-p (make-abbrev-table))))
(ert-deftest abbrev--possibly-save-test ()
"Test that `abbrev--possibly-save' properly resets
`abbrevs-changed'."
(ert-with-temp-file temp-test-file
(let ((abbrev-file-name temp-test-file)
(save-abbrevs t))
;; Save
(let ((abbrevs-changed t))
(should-not (abbrev--possibly-save nil t))
(should-not abbrevs-changed))
;; Don't save
(let ((abbrevs-changed t))
(ert-simulate-keys '(?n)
(should (abbrev--possibly-save nil)))
(should-not abbrevs-changed)))))
(provide 'abbrev-tests)
;;; abbrev-tests.el ends here

View file

@ -255,6 +255,27 @@ aliqua."
;;; Font-lock and syntax
(ert-deftest python-syntax-context-1 ()
(python-tests-with-temp-buffer
"
# Comment
s = 'Single Quoted String'
t = '''Triple Quoted String'''
p = (1 + 2)
"
(python-tests-look-at "Comment")
(should (= (python-syntax-context 'comment) (pos-bol)))
(python-tests-look-at "Single")
(should (= (python-syntax-context 'string) (1- (point))))
(should (= (python-syntax-context 'single-quoted-string) (1- (point))))
(should-not (python-syntax-context 'triple-quoted-string))
(python-tests-look-at "Triple")
(should (= (python-syntax-context 'string) (1- (point))))
(should-not (python-syntax-context 'single-quoted-string))
(should (= (python-syntax-context 'triple-quoted-string) (1- (point))))
(python-tests-look-at "1 + 2")
(should (= (python-syntax-context 'paren) (1- (point))))))
(ert-deftest python-syntax-after-python-backspace ()
;; `python-indent-dedent-line-backspace' garbles syntax
(python-tests-with-temp-buffer
@ -2052,6 +2073,54 @@ this is a test this is a test this is a test this is a test this is a test this
(fill-paragraph)
(should (= (current-indentation) 0))))
(ert-deftest python-fill-paragraph-single-quoted-string-1 ()
"Single quoted string should not be filled."
(let ((contents "
s = 'abc def ghi jkl mno pqr stu vwx yz'
")
(fill-column 20))
(python-tests-with-temp-buffer
contents
(python-tests-look-at "abc")
(fill-paragraph)
(should (string= (buffer-substring-no-properties (point-min) (point-max))
contents)))))
(ert-deftest python-fill-paragraph-single-quoted-string-2 ()
"Ensure no fill is performed after the end of the single quoted string."
(let ((contents "
s1 = 'abc'
s2 = 'def'
"))
(python-tests-with-temp-buffer
contents
(python-tests-look-at "abc")
(fill-paragraph)
(should (string= (buffer-substring-no-properties (point-min) (point-max))
contents)))))
(ert-deftest python-fill-paragraph-triple-quoted-string-1 ()
"Triple quoted string should be filled."
(let ((contents "
s = '''abc def ghi jkl mno pqr stu vwx yz'''
")
(expected "
s = '''abc def ghi
jkl mno pqr stu vwx
yz'''
")
(fill-column 20))
(dolist (look-at '("'''abc" "z'''"))
(dolist (offset '(0 1 2 3))
(python-tests-with-temp-buffer
contents
(python-tests-look-at look-at)
(forward-char offset)
(fill-paragraph)
(should (string=
(buffer-substring-no-properties (point-min) (point-max))
expected)))))))
;;; Mark
@ -6491,6 +6560,56 @@ class Class:
(python-tests-look-at "'''Not a method docstring.'''")
(should (not (python-info-docstring-p)))))
(ert-deftest python-info-triple-quoted-string-p-1 ()
"Test triple quoted string."
(python-tests-with-temp-buffer
"
t = '''Triple'''
"
(python-tests-look-at " '''Triple")
(should-not
(python-tests-should-not-move
#'python-info-triple-quoted-string-p))
(forward-char)
(let ((start-pos (+ (point) 2))
(eol (pos-eol)))
(while (< (point) eol)
(should (= (python-tests-should-not-move
#'python-info-triple-quoted-string-p)
start-pos))
(forward-char)))
(dolist (pos `(,(point) ,(point-min) ,(point-max)))
(goto-char pos)
(should-not
(python-tests-should-not-move
#'python-info-triple-quoted-string-p)))))
(ert-deftest python-info-triple-quoted-string-p-2 ()
"Test empty triple quoted string."
(python-tests-with-temp-buffer
"
e = ''''''
"
(python-tests-look-at "''''''")
(let ((start-pos (+ (point) 2))
(eol (pos-eol)))
(while (< (point) eol)
(should (= (python-tests-should-not-move
#'python-info-triple-quoted-string-p)
start-pos))
(forward-char)))))
(ert-deftest python-info-triple-quoted-string-p-3 ()
"Test single quoted string."
(python-tests-with-temp-buffer
"
s = 'Single'
"
(while (< (point) (point-max))
(should-not (python-tests-should-not-move
#'python-info-triple-quoted-string-p))
(forward-char))))
(ert-deftest python-info-encoding-from-cookie-1 ()
"Should detect it on first line."
(python-tests-with-temp-buffer