Following up on Different abbrevs for each major mode, which covers the first step that I found from here. And now, trying to cover to the next step.
In summary,
- the first step, i.e., Different abbrevs for each major mode, solves the problem of allowing abbreviations with leading "`" for each different major mode
- the next step, is to allow moving cursor into the proper position after expansion, which explained clearly in the above wiki
Please take a look at the code change at https://www.diffchecker.com/7TPMxkzU. It has two sides, which are two cases that I tried for the next step. They are basically all of my config, apart from load-path setting. On the left, everything is working; whereas on the right, abbreviations with leading "`" are not working any more. In details,
(define-abbrev-table 'python-mode-abbrev-table
'(
("fo" "bar")
("`foo" "bar")
("`p" "print()" ahf)
;;
))
The first two definitions:
("fo" "bar")
("`foo" "bar")
- with the config file on the left side, both are working.
- with the config file on the right side, only 1st working. 2nd is no longer working -- when I type "`foo" and press space, nothing happens.
The difference is the following code are being added:
;; == adapted from http://ergoemacs.org/emacs/elisp_abbrev.html
;; the “ahf” stand for abbrev hook function.
(defun ahf ()
"Abbrev hook function, used for `define-abbrev'.
prevent inserting the char that triggered expansion."
(interactive)
t)
(put 'ahf 'no-self-insert t)
(setq abbrev-expand-function 'global-expand-abbrev)
;; (setq abbrev-expand-function 'abbrev--default-expand)
(defun global-expand-abbrev ()
"Function for value of `abbrev-expand-function'.
Expand the symbol before cursor.
Returns the abbrev symbol if there's a expansion, else nil."
(interactive)
(let ( $p1 $p2
$abrStr
$abrSymbol
)
(save-excursion
(forward-symbol -1)
(setq $p1 (point))
(forward-symbol 1)
(setq $p2 (point)))
(setq $abrStr (buffer-substring-no-properties $p1 $p2))
(setq $abrSymbol (abbrev-symbol $abrStr))
(if $abrSymbol
(progn
(abbrev-insert $abrSymbol $abrStr $p1 $p2 )
(global-abbrev-position-cursor $p1)
$abrSymbol)
nil)))
(defun global-abbrev-position-cursor (&optional @pos)
"Move cursor (from @POS) back to ▮ if exist, else put at end.
Return true if found, else false."
(interactive)
(let (($found-p (search-backward "▮" (if @pos @pos (max (point-min) (- (point) 100))) t )))
(when $found-p (delete-char 1))
$found-p
))
I've made the above code work for abbreviations without leading "`", but now, when the two are put together, abbreviations with leading "`", and the above code, things are not working any more.
I don't know how to fix it as I don't know elisp except copying from working code.
Somebody help please.
PS. while you're at it, I'm also getting the following warning for above code:
Argument `@pos' should appear (as @POS) in the doc string (emacs-lisp-checkdoc)
which I have no idea how to fix either.
UPDATE:
I've documented my changes at https://www.diffchecker.com/BjiDYyJP, and set it to never expire. But just in case anything happens, here are the code again:
Before;; https://emacs.stackexchange.com/questions/66410/different-abbrevs-for-each-major-mode
(defvar my-abbrev-regexp
(rx (or bol (not (any "`" wordchar)))
(group (one-or-more (any "`" wordchar)))
(zero-or-more (not (any "`" wordchar))))
"Use as :regexp in abbrev tables to make \\=` a valid abbrev char.
If `words-include-escapes' is used then this regexp can fail.
Refer to the elisp comments in `abbrev--before-point' for details.")
(abbrev-table-put emacs-lisp-mode-abbrev-table :regexp my-abbrev-regexp)
(define-abbrev emacs-lisp-mode-abbrev-table "`foo" "bar")
(add-hook 'emacs-lisp-mode-hook #'abbrev-mode)
;; use it with a mode which is not loaded by default
(with-eval-after-load "sh-script"
(abbrev-table-put sh-mode-abbrev-table :regexp my-abbrev-regexp)
(define-abbrev sh-mode-abbrev-table "`foo" "bar")
(add-hook 'sh-mode-hook #'abbrev-mode))
(progn
;; python
(when (boundp 'python-mode-abbrev-table)
(clear-abbrev-table python-mode-abbrev-table))
(define-abbrev-table 'python-mode-abbrev-table
'(
("fo" "bar")
("p" "print(▮)" ahf)
("`foo" "bar")
("`p" "print()" ahf)
;;
))
(abbrev-table-put python-mode-abbrev-table :regexp my-abbrev-regexp)
(add-hook 'python-mode-hook #'abbrev-mode)
)
;; == adapted from http://ergoemacs.org/emacs/elisp_abbrev.html
;; the “ahf” stand for abbrev hook function.
(defun ahf ()
"Abbrev hook function, used for `define-abbrev'.
prevent inserting the char that triggered expansion."
(interactive)
t)
(put 'ahf 'no-self-insert t)
(setq abbrev-expand-function 'global-expand-abbrev)
;; (setq abbrev-expand-function 'abbrev--default-expand)
(defun global-expand-abbrev ()
"Function for value of `abbrev-expand-function'.
Expand the symbol before cursor.
Returns the abbrev symbol if there's a expansion, else nil."
(interactive)
(let ( $p1 $p2
$abrStr
$abrSymbol
)
(save-excursion
(forward-symbol -1)
(setq $p1 (point))
(forward-symbol 1)
(setq $p2 (point)))
(setq $abrStr (buffer-substring-no-properties $p1 $p2))
(setq $abrSymbol (abbrev-symbol $abrStr))
(if $abrSymbol
(progn
(abbrev-insert $abrSymbol $abrStr $p1 $p2 )
(global-abbrev-position-cursor $p1)
$abrSymbol)
nil)))
(defun global-abbrev-position-cursor (&optional @pos)
"Move cursor (from @POS) back to ▮ if exist, else put at end.
Return true if found, else false."
(interactive)
(let (($found-p (search-backward "▮" (if @pos @pos (max (point-min) (- (point) 100))) t )))
(when $found-p (delete-char 1))
$found-p
))
(setq save-abbrevs nil)
After
;; https://emacs.stackexchange.com/questions/66410/different-abbrevs-for-each-major-mode
(defvar my-abbrev-regexp
"\\(`[0-9A-Za-z._-]+\\)"
"Use as :regexp in abbrev tables to make \\=` a valid abbrev char.
If making \\=` optional (suffix it with ?), `re-search-backward' will
not be able to be that aggressive to match to it. Thus, making
the leading \\=` mandatory.
If `words-include-escapes' is used then this regexp can fail.
Refer to the elisp comments in `abbrev--before-point' for details.")
(abbrev-table-put emacs-lisp-mode-abbrev-table :regexp my-abbrev-regexp)
(define-abbrev emacs-lisp-mode-abbrev-table "`foo" "bar")
(add-hook 'emacs-lisp-mode-hook #'abbrev-mode)
;; use it with a mode which is not loaded by default
(with-eval-after-load "sh-script"
(abbrev-table-put sh-mode-abbrev-table :regexp my-abbrev-regexp)
(define-abbrev sh-mode-abbrev-table "`foo" "bar")
(add-hook 'sh-mode-hook #'abbrev-mode))
(progn
;; python
(when (boundp 'python-mode-abbrev-table)
(clear-abbrev-table python-mode-abbrev-table))
(define-abbrev-table 'python-mode-abbrev-table
'(
("`foo" "bar")
("`p" "print(▮)" ahf)
;;
))
(abbrev-table-put python-mode-abbrev-table :regexp my-abbrev-regexp)
(add-hook 'python-mode-hook #'abbrev-mode)
)
;; == adapted from http://ergoemacs.org/emacs/elisp_abbrev.html
;; the “ahf” stand for abbrev hook function.
(defun ahf ()
"Abbrev hook function, used for `define-abbrev'.
prevent inserting the char that triggered expansion."
(interactive)
t)
(put 'ahf 'no-self-insert t)
(setq abbrev-expand-function 'global-expand-abbrev)
;; (setq abbrev-expand-function 'abbrev--default-expand)
(defun global-expand-abbrev ()
"Function for value of `abbrev-expand-function'.
Expand the symbol before cursor.
Returns the abbrev symbol if there's a expansion, else nil."
(interactive)
(let ( $p1 $p2
$abrStr
$abrSymbol
)
(save-excursion
;; (forward-symbol -1)
(re-search-backward my-abbrev-regexp)
(setq $p1 (point))
(forward-symbol 1)
(setq $p2 (point)))
(setq $abrStr (buffer-substring-no-properties $p1 $p2))
(setq $abrSymbol (abbrev-symbol $abrStr))
(if $abrSymbol
(progn
(abbrev-insert $abrSymbol $abrStr $p1 $p2 )
(global-abbrev-position-cursor $p1)
$abrSymbol)
nil)))
(defun global-abbrev-position-cursor (&optional @pos)
"Move cursor (from @POS) back to ▮ if exist, else put at end.
Return true if found, else false."
(interactive)
(let (($found-p (search-backward "▮" (if @pos @pos (max (point-min) (- (point) 100))) t )))
(when $found-p (delete-char 1))
$found-p
))
(setq save-abbrevs nil)
NB my above solution is different from phils answer, which accepted as the correct answer, and it'll remain that way.
ahf
function is not the source of the problem. I.e., the source of the problem is only the added two new functions,global-expand-abbrev
, andglobal-abbrev-position-cursor
, which I had validated that they both work for case without the leading "`". If you don't want to answer it, please leave it for somebody else. thanks.