mirror of
https://github.com/joaotavora/yasnippet.git
synced 2025-10-13 13:13:03 +00:00
Checking in still largely failing attempt on nested placeholders,,,
This commit is contained in:
parent
7a0ee29afa
commit
cc0211316e
253
yasnippet.el
253
yasnippet.el
@ -91,14 +91,31 @@ mode will be listed under the menu \"yasnippet\".")
|
|||||||
(defvar yas/trigger-symbol " =>"
|
(defvar yas/trigger-symbol " =>"
|
||||||
"The text that will be used in menu to represent the trigger.")
|
"The text that will be used in menu to represent the trigger.")
|
||||||
|
|
||||||
(defface yas/field-highlight-face
|
|
||||||
'((((class color) (background light)) (:background "DarkSeaGreen2"))
|
(defun yas/define-multiple-faces (prefix background-color-pairs &optional doc)
|
||||||
(t (:background "DimGrey")))
|
"TODO: describe this rebuscated function"
|
||||||
"The face used to highlight a field of snippet.")
|
(mapcar #'(lambda (color-pair)
|
||||||
(defface yas/mirror-highlight-face
|
(let* ((depth (position color-pair background-color-pairs)))
|
||||||
'((((class color) (background light)) (:background "LightYellow2"))
|
(when depth
|
||||||
(t (:background "gray22")))
|
(eval `(defface ,(intern (format "%s-%d" prefix depth))
|
||||||
"The face used to highlight mirror fields of a snippet.")
|
'((((class color) (background light)) (:background ,(first color-pair)))
|
||||||
|
(t (:background ,(second color-pair))))
|
||||||
|
,(when doc
|
||||||
|
(format "%s %d." doc depth)))))))
|
||||||
|
background-color-pairs))
|
||||||
|
|
||||||
|
;; Define multiple faces up to nested field (and mirror) depth 4
|
||||||
|
(eval-when-compile
|
||||||
|
(yas/define-multiple-faces "yas/field-highlight-face" `(("DarkSeaGreen1" "DimGrey")
|
||||||
|
("DarkSeaGreen3" "SlateGrey")
|
||||||
|
("DarkOliveGreen2" "LightSlateGrey")
|
||||||
|
("DarkOliveGreen4" "Gray"))
|
||||||
|
"The face used to highlight a field of a snippet with depth ")
|
||||||
|
(yas/define-multiple-faces "yas/mirror-highlight-face" `(("LightYellow1" "gray22")
|
||||||
|
("LightYellow3" "grey32")
|
||||||
|
("khaki2" "grey42")
|
||||||
|
("khaki4" "grey52"))
|
||||||
|
"The face used to highlight mirror fields of a snippet with depth "))
|
||||||
|
|
||||||
(defvar yas/window-system-popup-function #'yas/dropdown-list-popup-for-template
|
(defvar yas/window-system-popup-function #'yas/dropdown-list-popup-for-template
|
||||||
"When there's multiple candidate for a snippet key. This function
|
"When there's multiple candidate for a snippet key. This function
|
||||||
@ -318,12 +335,13 @@ TODO: describe the rest of the fields"
|
|||||||
(prev nil)
|
(prev nil)
|
||||||
snippet)
|
snippet)
|
||||||
(defstruct (yas/field
|
(defstruct (yas/field
|
||||||
(:constructor yas/make-field (overlay number value transform)))
|
(:constructor yas/make-field (overlay number value transform parent-field)))
|
||||||
"A field in a snippet."
|
"A field in a snippet."
|
||||||
overlay
|
overlay
|
||||||
number
|
number
|
||||||
transform
|
transform
|
||||||
value)
|
value
|
||||||
|
parent-field)
|
||||||
(defstruct (yas/snippet-table (:constructor yas/make-snippet-table ()))
|
(defstruct (yas/snippet-table (:constructor yas/make-snippet-table ()))
|
||||||
"A table to store snippets for a perticular mode."
|
"A table to store snippets for a perticular mode."
|
||||||
(hash (make-hash-table :test 'equal))
|
(hash (make-hash-table :test 'equal))
|
||||||
@ -336,7 +354,10 @@ TODO: describe the rest of the fields"
|
|||||||
(not (null (overlay-start (yas/snippet-overlay snippet))))))
|
(not (null (overlay-start (yas/snippet-overlay snippet))))))
|
||||||
|
|
||||||
(defun yas/snippet-add-field (snippet field)
|
(defun yas/snippet-add-field (snippet field)
|
||||||
"Add FIELD to SNIPPET."
|
"Add FIELD to the correct group of SNIPPET.
|
||||||
|
|
||||||
|
If no group is found, create one using `yas/make-group'. Return
|
||||||
|
FIELD."
|
||||||
(let ((group (find field
|
(let ((group (find field
|
||||||
(yas/snippet-groups snippet)
|
(yas/snippet-groups snippet)
|
||||||
:test
|
:test
|
||||||
@ -348,7 +369,8 @@ TODO: describe the rest of the fields"
|
|||||||
(if group
|
(if group
|
||||||
(yas/group-add-field group field)
|
(yas/group-add-field group field)
|
||||||
(push (yas/make-group field snippet)
|
(push (yas/make-group field snippet)
|
||||||
(yas/snippet-groups snippet)))))
|
(yas/snippet-groups snippet)))
|
||||||
|
field))
|
||||||
|
|
||||||
(defun yas/group-value (group)
|
(defun yas/group-value (group)
|
||||||
"Get the default value of the field group."
|
"Get the default value of the field group."
|
||||||
@ -620,21 +642,33 @@ redo-ed."
|
|||||||
start))
|
start))
|
||||||
(insert key)))
|
(insert key)))
|
||||||
|
|
||||||
(defun yas/replace-fields-with-value (fields text)
|
(defun yas/replace-fields-with-value (fields &optional rep)
|
||||||
"In all of the fields of the snippet group GROUP fields, delete
|
;; TODO: revise need for this rebuscatedeness
|
||||||
whatever value (string) existed and insert TEXT instead.
|
;; "For all FIELDS, delete characters outside the field's value
|
||||||
|
;; in field's overlay region.
|
||||||
|
|
||||||
The string to insert is calculated according to
|
;; This default behaviour ensures other overlays covered by the same
|
||||||
`yas/calculate-field-value', which might insert different text
|
;; region are not innapropriately displaced.
|
||||||
for each field."
|
|
||||||
|
;; With optional parameter REP, replace the field with delete whatever value (string)
|
||||||
|
;; existed and insert the field's text instead instead.
|
||||||
|
|
||||||
|
;; In both cases, to enable producing different replacements for
|
||||||
|
;; each field, the replacement is calculated according to
|
||||||
|
;; `yas/calculate-field-value', which is passed the field itself,
|
||||||
|
;; and, as the second paramenter ,the value of `yas/field-value' or
|
||||||
|
;; REP if it is non-nil"
|
||||||
(dolist (field fields)
|
(dolist (field fields)
|
||||||
(let* ((overlay (yas/field-overlay field))
|
(let* ((overlay (yas/field-overlay field))
|
||||||
(start (overlay-start overlay))
|
(start (overlay-start overlay))
|
||||||
(end (overlay-end overlay))
|
(end (overlay-end overlay))
|
||||||
(length (- end start)))
|
(length (- end start))
|
||||||
(goto-char start)
|
(text (yas/calculate-field-value field (or rep
|
||||||
(insert (yas/calculate-field-value field text))
|
(yas/field-value field)))))
|
||||||
(delete-char length))))
|
(when text
|
||||||
|
(goto-char start)
|
||||||
|
(insert text)
|
||||||
|
(delete-char length)))))
|
||||||
|
|
||||||
(defun yas/expand-snippet (start end template)
|
(defun yas/expand-snippet (start end template)
|
||||||
"Expand snippet at current point. Text between START and END
|
"Expand snippet at current point. Text between START and END
|
||||||
@ -688,27 +722,7 @@ will be deleted before inserting template."
|
|||||||
;; `yas/registered-snippets' var. Create fields.
|
;; `yas/registered-snippets' var. Create fields.
|
||||||
(let ((snippet (yas/register-snippet (yas/make-snippet))))
|
(let ((snippet (yas/register-snippet (yas/make-snippet))))
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(while (re-search-forward yas/field-regexp nil t)
|
(yas/field-parse-create snippet)
|
||||||
(let ((number (or (match-string-no-properties 1)
|
|
||||||
(match-string-no-properties 2)))
|
|
||||||
(transform nil)
|
|
||||||
(value (match-string-no-properties 3)))
|
|
||||||
(when (eq (elt value 0) ?\$)
|
|
||||||
(setq transform (substring value 1))
|
|
||||||
(setq value nil))
|
|
||||||
(if (and number
|
|
||||||
(string= "0" number))
|
|
||||||
(progn
|
|
||||||
(replace-match "")
|
|
||||||
(setf (yas/snippet-exit-marker snippet)
|
|
||||||
(copy-marker (point) t)))
|
|
||||||
(yas/snippet-add-field
|
|
||||||
snippet
|
|
||||||
(yas/make-field
|
|
||||||
(make-overlay (match-beginning 0) (match-end 0))
|
|
||||||
(and number (string-to-number number))
|
|
||||||
value
|
|
||||||
transform)))))
|
|
||||||
|
|
||||||
;; Step 6: Sort and link each field group
|
;; Step 6: Sort and link each field group
|
||||||
(setf (yas/snippet-groups snippet)
|
(setf (yas/snippet-groups snippet)
|
||||||
@ -741,10 +755,14 @@ will be deleted before inserting template."
|
|||||||
(setf (yas/snippet-overlay snippet) overlay)
|
(setf (yas/snippet-overlay snippet) overlay)
|
||||||
(setf (yas/snippet-end-marker snippet) (overlay-end overlay)))
|
(setf (yas/snippet-end-marker snippet) (overlay-end overlay)))
|
||||||
|
|
||||||
;; Step 8: Replace fields with default values
|
;; Step 8: Replace mirror field values with primary group's
|
||||||
|
;; value
|
||||||
(dolist (group (yas/snippet-groups snippet))
|
(dolist (group (yas/snippet-groups snippet))
|
||||||
(yas/replace-fields-with-value (yas/group-fields group)
|
(yas/replace-fields-with-value
|
||||||
(yas/group-value group)))
|
(remove-if #'(lambda (field)
|
||||||
|
(eq (yas/group-primary-field group) field))
|
||||||
|
(yas/group-fields group))
|
||||||
|
(yas/group-value group)))
|
||||||
|
|
||||||
;; Step 9: restore all escape characters
|
;; Step 9: restore all escape characters
|
||||||
(yas/replace-all yas/escape-dollar "$")
|
(yas/replace-all yas/escape-dollar "$")
|
||||||
@ -760,12 +778,13 @@ will be deleted before inserting template."
|
|||||||
(overlay-put overlay 'yas/modified? nil)
|
(overlay-put overlay 'yas/modified? nil)
|
||||||
(overlay-put overlay 'modification-hooks yas/overlay-modification-hooks)
|
(overlay-put overlay 'modification-hooks yas/overlay-modification-hooks)
|
||||||
(overlay-put overlay 'insert-in-front-hooks yas/overlay-insert-in-front-hooks)
|
(overlay-put overlay 'insert-in-front-hooks yas/overlay-insert-in-front-hooks)
|
||||||
(overlay-put overlay 'face 'yas/field-highlight-face)
|
(overlay-put overlay
|
||||||
|
'face (intern (format "yas/field-highlight-face-%d"
|
||||||
|
(overlay-get overlay 'priority))))
|
||||||
(dolist (field (yas/group-fields group))
|
(dolist (field (yas/group-fields group))
|
||||||
(unless (equal overlay (yas/field-overlay field))
|
(unless (equal overlay (yas/field-overlay field))
|
||||||
(overlay-put (yas/field-overlay field)
|
(overlay-put (yas/field-overlay field)
|
||||||
'face
|
'face (intern (format "yas/mirror-highlight-face-%d" (overlay-get overlay 'priority))))))))
|
||||||
'yas/mirror-highlight-face)))))
|
|
||||||
|
|
||||||
;; Step 11: move to end and make sure exit-marker exist
|
;; Step 11: move to end and make sure exit-marker exist
|
||||||
(goto-char (point-max))
|
(goto-char (point-max))
|
||||||
@ -806,6 +825,114 @@ will be deleted before inserting template."
|
|||||||
(replace-match "")
|
(replace-match "")
|
||||||
(indent-according-to-mode)))))))
|
(indent-according-to-mode)))))))
|
||||||
|
|
||||||
|
(defun yas/field-parse-create (snippet &optional parent-field)
|
||||||
|
"Parse a recently inserted snippet template, creating all
|
||||||
|
necessary fields.
|
||||||
|
|
||||||
|
Allows nested placeholder in the style of Textmate."
|
||||||
|
;; 5. Search from current point for yas/field-regexp
|
||||||
|
;;
|
||||||
|
;; a) That is, look for "$<`number'>" or
|
||||||
|
;; "${<`number'>:<`value'>}". A few special cases.
|
||||||
|
;;
|
||||||
|
;; b) When `value' starts with $, assume the rest is a lisp
|
||||||
|
;; expression returning string. assign that to `transform'
|
||||||
|
;;
|
||||||
|
;; A transformation is signalled when `value' starts with the
|
||||||
|
;; character "$" as the first value after the ":". The rest of
|
||||||
|
;; `value' is not allowed to have any other nested snippet
|
||||||
|
;; definitions. Don't know if Textmate allows this...
|
||||||
|
;;
|
||||||
|
;; c) If `number' is 0 (zero) the string found is deleted and
|
||||||
|
;; that special place is the snippet's exit marker...
|
||||||
|
;;
|
||||||
|
;; d) Otherwise a placeholder field for `number' is added to the
|
||||||
|
;; snippet with `value' and `transform'.
|
||||||
|
;;
|
||||||
|
;; e) Then, still, buffer is temporarily narrowed down to `value'
|
||||||
|
;; and `yas/field-parse-create' is called again recursively
|
||||||
|
;; with the recently created field as `parent-field'. That
|
||||||
|
;; might actually add more fields.
|
||||||
|
;;
|
||||||
|
;; f) In any case, point is moved to just after the closing bracket
|
||||||
|
;; after `value' and the search starts again from a).
|
||||||
|
;;
|
||||||
|
;;
|
||||||
|
(while (re-search-forward yas/field-regexp nil t)
|
||||||
|
(let* ((number (or (match-string-no-properties 1)
|
||||||
|
(match-string-no-properties 2)))
|
||||||
|
(transform nil)
|
||||||
|
(bracket-end (set-marker (make-marker)
|
||||||
|
(yas/field-bracket-end)))
|
||||||
|
(value-start (set-marker (make-marker) (match-beginning 3)))
|
||||||
|
(value-end (set-marker (make-marker)
|
||||||
|
(or (and (marker-position bracket-end)
|
||||||
|
(1- bracket-end))
|
||||||
|
(match-end 3))))
|
||||||
|
(value (when (and (marker-position value-start)
|
||||||
|
(marker-position value-end))
|
||||||
|
(buffer-substring-no-properties value-start value-end)))
|
||||||
|
brand-new-field)
|
||||||
|
;; b) look for a transformation
|
||||||
|
(when (eq (elt value 0) ?\$)
|
||||||
|
(setq transform (substring value 1))
|
||||||
|
(setq value nil))
|
||||||
|
(if (and number
|
||||||
|
(string= "0" number))
|
||||||
|
;; c) set exit marker and forget
|
||||||
|
(progn
|
||||||
|
(replace-match "")
|
||||||
|
(setf (yas/snippet-exit-marker snippet)
|
||||||
|
(copy-marker (point) t)))
|
||||||
|
;; d) add field
|
||||||
|
(setq brand-new-field
|
||||||
|
(yas/snippet-add-field
|
||||||
|
snippet
|
||||||
|
(yas/make-field
|
||||||
|
(make-overlay (match-beginning 0) (or (marker-position bracket-end)
|
||||||
|
(match-end 0)))
|
||||||
|
(and number (string-to-number number))
|
||||||
|
value
|
||||||
|
transform
|
||||||
|
parent-field)))
|
||||||
|
;; e) set correct overlay priority
|
||||||
|
(overlay-put (yas/field-overlay brand-new-field) 'priority
|
||||||
|
(if parent-field
|
||||||
|
(1+ (overlay-get (yas/field-overlay parent-field)
|
||||||
|
'priority))
|
||||||
|
0))
|
||||||
|
(when value
|
||||||
|
;; f) delete useless regions, move to correct spot for more
|
||||||
|
;; search...
|
||||||
|
(when (marker-position bracket-end)
|
||||||
|
(delete-region value-end bracket-end))
|
||||||
|
(delete-region (match-beginning 0) value-start)
|
||||||
|
;; g) investigate nested placeholders
|
||||||
|
(save-excursion
|
||||||
|
(save-restriction
|
||||||
|
(narrow-to-region value-start value-end)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(yas/field-parse-create snippet brand-new-field))))))))
|
||||||
|
|
||||||
|
(defun yas/field-bracket-end ()
|
||||||
|
"Calculates position of the field's closing bracket if any.
|
||||||
|
|
||||||
|
Assumes a regexp search for `yas/field-regexp' matched
|
||||||
|
recently. Return Nil if no field value subexpression was found,
|
||||||
|
or throws error if the snippet has malformed nested
|
||||||
|
placeholders."
|
||||||
|
(let ((bracket-or-number-start (1+ (match-beginning 0)))
|
||||||
|
bracket-end)
|
||||||
|
(when (eq ?\{ (char-after bracket-or-number-start))
|
||||||
|
(setq bracket-end (condition-case oops
|
||||||
|
(scan-sexps bracket-or-number-start 1)
|
||||||
|
;; TODO: Later should throw another error with
|
||||||
|
;; information about failed syntax!
|
||||||
|
(error
|
||||||
|
(message "Invalid snippet template!")))))
|
||||||
|
bracket-end))
|
||||||
|
|
||||||
|
|
||||||
(defun yas/current-snippet-overlay (&optional point)
|
(defun yas/current-snippet-overlay (&optional point)
|
||||||
"Get the most proper overlay which is belongs to a snippet."
|
"Get the most proper overlay which is belongs to a snippet."
|
||||||
(let ((point (or point (point)))
|
(let ((point (or point (point)))
|
||||||
@ -1356,17 +1483,23 @@ current buffer."
|
|||||||
"Cleanup SNIPPET, but leave point as it is. This renders the
|
"Cleanup SNIPPET, but leave point as it is. This renders the
|
||||||
snippet as ordinary text"
|
snippet as ordinary text"
|
||||||
(let* ((overlay (yas/snippet-overlay snippet))
|
(let* ((overlay (yas/snippet-overlay snippet))
|
||||||
(yas/snippet-beg (overlay-start overlay))
|
yas/snippet-beg yas/snippet-end)
|
||||||
(yas/snippet-end (overlay-end overlay)))
|
|
||||||
;; save the end of the moribund snippet in case we need to undo
|
;; save the end of the moribund snippet in case we need to undo
|
||||||
;; its original expansion. This is used by `yas/undo-expand-snippet'
|
;; its original expansion. This is used by `yas/undo-expand-snippet'
|
||||||
(when (and overlay
|
(when (and overlay
|
||||||
(overlay-buffer overlay))
|
(overlay-buffer overlay))
|
||||||
|
(setq yas/snippet-beg (overlay-start overlay))
|
||||||
|
(setq yas/snippet-end (overlay-end overlay))
|
||||||
(setf (yas/snippet-end-marker snippet) yas/snippet-end)
|
(setf (yas/snippet-end-marker snippet) yas/snippet-end)
|
||||||
(delete-overlay overlay))
|
(delete-overlay overlay))
|
||||||
(dolist (group (yas/snippet-groups snippet))
|
(dolist (group (yas/snippet-groups snippet))
|
||||||
(dolist (field (yas/group-fields group))
|
(dolist (field (yas/group-fields group))
|
||||||
(delete-overlay (yas/field-overlay field))))
|
(delete-overlay (yas/field-overlay field))))
|
||||||
|
;; XXX: `yas/after-exit-snippet-hook' should be run with
|
||||||
|
;; `yas/snippet-beg' and `yas/snippet-end' bound. That might not
|
||||||
|
;; be the case if the main overlay had somehow already
|
||||||
|
;; disappeared, which sometimes happens when the snippet's messed
|
||||||
|
;; up...
|
||||||
(run-hooks 'yas/after-exit-snippet-hook))
|
(run-hooks 'yas/after-exit-snippet-hook))
|
||||||
(yas/unregister-snippet snippet)
|
(yas/unregister-snippet snippet)
|
||||||
(setq buffer-undo-list (yas/snippet-saved-buffer-undo-list snippet)))
|
(setq buffer-undo-list (yas/snippet-saved-buffer-undo-list snippet)))
|
||||||
@ -1446,9 +1579,10 @@ is pushed into this variable and it then replaces
|
|||||||
should not trigger any undo-recording action")
|
should not trigger any undo-recording action")
|
||||||
|
|
||||||
(defun yas/field-undo-before-hook ()
|
(defun yas/field-undo-before-hook ()
|
||||||
"Saves the field-level undo history, `buffer-undo-list' into a global
|
"Saves the field-level undo history, `buffer-undo-list' into a
|
||||||
`yas/field-undo-history' variable just before a command is
|
global `yas/field-undo-history' variable just before a command is
|
||||||
performed. It will come in handy in case the command is to be undone"
|
performed. That variable will come in handy in case the command
|
||||||
|
is to be undone"
|
||||||
(setq yas/field-undo-history buffer-undo-list))
|
(setq yas/field-undo-history buffer-undo-list))
|
||||||
|
|
||||||
(defun yas/field-undo-after-hook ()
|
(defun yas/field-undo-after-hook ()
|
||||||
@ -1482,7 +1616,7 @@ be a part of that list while registered snippets last."
|
|||||||
;; there first. Have no clue why sometimes one is and one
|
;; there first. Have no clue why sometimes one is and one
|
||||||
;; isn't.
|
;; isn't.
|
||||||
;;
|
;;
|
||||||
(unless (null (car yas/field-undo-history))
|
(unless (null (car-safe yas/field-undo-history))
|
||||||
(push nil yas/field-undo-history))
|
(push nil yas/field-undo-history))
|
||||||
(push `(apply yas/field-undo-group-text-change
|
(push `(apply yas/field-undo-group-text-change
|
||||||
,group
|
,group
|
||||||
@ -1517,7 +1651,9 @@ be a part of that list while registered snippets last."
|
|||||||
(with-output-to-temp-buffer "*YASnippet trace*"
|
(with-output-to-temp-buffer "*YASnippet trace*"
|
||||||
(princ "Interesting YASnippet vars: \n\n")
|
(princ "Interesting YASnippet vars: \n\n")
|
||||||
(princ (format "Register hash-table: %s\n\n" yas/registered-snippets))
|
(princ (format "Register hash-table: %s\n\n" yas/registered-snippets))
|
||||||
(cond ((eq (hash-table-count yas/registered-snippets) 0)
|
(cond ((not yas/registered-snippets)
|
||||||
|
(princ " No snippet hash table!"))
|
||||||
|
((eq (hash-table-count yas/registered-snippets) 0)
|
||||||
(princ " No registered snippets\n"))
|
(princ " No registered snippets\n"))
|
||||||
(t
|
(t
|
||||||
(maphash #'(lambda (key snippet)
|
(maphash #'(lambda (key snippet)
|
||||||
@ -1526,7 +1662,8 @@ be a part of that list while registered snippets last."
|
|||||||
(yas/snippet-id snippet)
|
(yas/snippet-id snippet)
|
||||||
(length (yas/snippet-groups snippet))))
|
(length (yas/snippet-groups snippet))))
|
||||||
(dolist (group (yas/snippet-groups snippet))
|
(dolist (group (yas/snippet-groups snippet))
|
||||||
(princ (format "\t group with %s fields. Primary field is value is \"%s\"\n"
|
(princ (format "\t group $%s with %s fields. Primary field is value is \"%s\"\n"
|
||||||
|
(yas/group-number group)
|
||||||
(length (yas/group-fields group))
|
(length (yas/group-fields group))
|
||||||
(yas/field-value (yas/group-primary-field group))))))
|
(yas/field-value (yas/group-primary-field group))))))
|
||||||
yas/registered-snippets)))
|
yas/registered-snippets)))
|
||||||
@ -1542,7 +1679,7 @@ be a part of that list while registered snippets last."
|
|||||||
(let ((undo-list buffer-undo-list))
|
(let ((undo-list buffer-undo-list))
|
||||||
(dotimes (i 10)
|
(dotimes (i 10)
|
||||||
(when undo-list
|
(when undo-list
|
||||||
(princ (format "%s: %s\n" i (car undo-list)))
|
(princ (format "%s: %s\n" i (car-safe undo-list)))
|
||||||
(setq undo-list (cdr undo-list)))))))
|
(setq undo-list (cdr undo-list)))))))
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user