How to query syntax class constituents as string of char? - emacs

Using elisp I am trying to convert from an emacs syntax class \s_ to a string of characters that constitute this class using the syntax table. I have not been able to find some reference code or an example that I could identify.
Does anyone have a reference or a code snippet to share?
Thanks, Matt
Update 1 : After further reading, I have found that the table can be traversed with map-char-table, accumulating the required characters.

Some utilities in use here from
https://launchpad.net/s-x-emacs-werkstatt/
(defun ar-syntax-class-atpt (&optional pos)
"Return the syntax class part of the syntax at point. "
(interactive)
(let* ((pos (or pos (point)))
(erg (logand (car (syntax-after pos)) 65535)))
(when (interactive-p) (message "%s" erg)) erg))
(defun syntax-class-bfpt ()
"Return the syntax class part of the syntax at point. "
(interactive)
(let ((erg (logand (car (syntax-after (1- (point)))) 65535)))
(when (interactive-p) (message "%s" erg)) erg))
(defun ar-syntax-atpt (&optional docu pos)
(interactive)
(when pos
(goto-char pos))
(let* ((elt (car (if (featurep 'xemacs)
(char-syntax (char-after))
(syntax-after (point)))))
(stax (cond ((eq elt 0) "0 whitespace")
((eq elt 5) "5 close parenthesis")
((eq elt 10) "10 character quote")
((eq elt 1) "1 punctuation")
((eq elt 6) "6 expression prefix")
((eq elt 11) "11 comment-start")
((eq elt 2) "2 word")
((eq elt 7) "7 string quote")
((eq elt 12) "12 comment-end")
((eq elt 3) "3 symbol")
((eq elt 8) "8 paired delimiter")
((eq elt 13) "13 inherit")
((eq elt 4) "4 open parenthesis")
((eq elt 9) "9 escape")
((eq elt 14) "14 generic comment")
((eq elt 15) "15 generic string"))))
(when (interactive-p)
(message (format "%s" stax)))
(if docu
(format "%s" stax)
elt)))
(defun ar-syntax-in-region-atpt (beg end)
(interactive "r")
(save-excursion
(goto-char beg)
(let (erg)
(while (< (point) end)
(setq erg (concat erg "\n" "\"" (char-to-string (char-after)) "\"" " is " (ar-syntax-atpt t)))
(forward-char 1))
(message "%s" erg)
erg)))
(defun syntax-bfpt ()
(interactive)
(let ((stax (syntax-after (1- (point)))))
(when (interactive-p)
(message (format "%s" stax)))
stax))

Related

Destructuring bind for regex matches

In elisp, how can I get a destructuring bind for regex matches?
For example,
;; what is the equivalent of this with destructuring?
(with-temp-buffer
(save-excursion (insert "a b"))
(re-search-forward "\\(a\\) \\(b\\)")
(cons (match-string 1)
(match-string 2)))
;; trying to do something like the following
(with-temp-buffer
(save-excursion (insert "a b"))
(cl-destructuring-bind (a b) (re-search-forward "\\(a\\) \\(b\\)")
(cons a b)))
I was thinking I would have to write a macro to expand matches if there isn't another way.
Here is one way: you first extend pcase to accept a new re-match pattern, with a definition such as:
(pcase-defmacro re-match (re)
"Matches a string if that string matches RE.
RE should be a regular expression (a string).
It can use the special syntax \\(?VAR: to bind a sub-match
to variable VAR. All other subgroups will be treated as shy.
Multiple uses of this macro in a single `pcase' are not optimized
together, so don't expect lex-like performance. But in order for
such optimization to be possible in some distant future, back-references
are not supported."
(let ((start 0)
(last 0)
(new-re '())
(vars '())
(gn 0))
(while (string-match "\\\\(\\(?:\\?\\([-[:alnum:]]*\\):\\)?" re start)
(setq start (match-end 0))
(let ((beg (match-beginning 0))
(name (match-string 1 re)))
;; Skip false positives, either backslash-escaped or within [...].
(when (subregexp-context-p re start last)
(cond
((null name)
(push (concat (substring re last beg) "\\(?:") new-re))
((string-match "\\`[0-9]" name)
(error "Variable can't start with a digit: %S" name))
(t
(let* ((var (intern name))
(id (cdr (assq var vars))))
(unless id
(setq gn (1+ gn))
(setq id gn)
(push (cons var gn) vars))
(push (concat (substring re last beg) (format "\\(?%d:" id))
new-re))))
(setq last start))))
(push (substring re last) new-re)
(setq new-re (mapconcat #'identity (nreverse new-re) ""))
`(and (pred stringp)
(app (lambda (s)
(save-match-data
(when (string-match ,new-re s)
(vector ,#(mapcar (lambda (x) `(match-string ,(cdr x) s))
vars)))))
(,'\` [,#(mapcar (lambda (x) (list '\, (car x))) vars)])))))
and once that is done, you can use it as follows:
(pcase X
((re-match "\\(?var:[[:alpha:]]*\\)=\\(?val:.*\\)")
(cons var val)))
or
(pcase-let
(((re-match "\\(?var:[[:alpha:]]*\\)=\\(?val:.*\\)") X))
(cons var val))
This has not been heavily tested, and as mentioned in the docstring it doesn't work as efficiently as it (c|sh)ould when matching a string against various regexps at the same time. Also you only get the matched substrings, not their position. And finally, it applies the regexp search to a string, whereas in manny/most cases regexps searches are used in a buffer. But you may still find it useful.

Replace character at point in Emacs

Is it there any function to replace character at point in Emacs Lisp?
Currently what I can do is:
(goto-char pt)
(delete-char 1)
(insert c)
I don't think there's a function to do that, but of course you can wrap the above in a defun.
There are some common replacements, for example toggle the case, switch "(" to ")", raise/lower a number. Might be done with the following:
(defun reverse-chars (&optional arg)
"Reverse reciproke chars as \"[\" to \"]\", upcase or downcase,
Switch `\"' with `''
If over a number, add ARG to it.
With negative arg, substract from number.
Et EOB, look backward for next number. "
(interactive "*p")
(let (i done)
(if (looking-at "[0-9]")
(ar-add-to-number arg)
(let* ((cf (char-after))
(cn (when (char-or-string-p cf)(downcase cf))))
(cond ((or (eobp)(eq cf 32)(eq cf ?\ ))
(when (< 0 (abs (skip-chars-backward "^0-9" (line-beginning-position))))
(forward-char -1)
(ar-add-to-number arg)
(setq done t)))
((eq cf 34) ;; ?\"
(setq cn "'"))
((eq cf 39) ;; ?\'
(setq cn "\""))
((eq cf 43) ;; ?\+
(setq cn "-"))
((eq cf 62) ;; ?\>
(setq cn "<"))
((eq cf 60) ;; ?\<
(setq cn ">"))
((eq cf 187) ;; ?\»
(setq cn "«"))
((eq cf 171) ;; ?\«
(setq cn "»"))
((eq cf 41) ;; ?\)
(setq cn "("))
((eq cf 40) ;; ?\(
(setq cn ")"))
((eq cf 123)
(setq cn "}"))
((eq cf 125)
(setq cn "{"))
((eq cf 93) ;; ?\]
(setq cn "["))
((eq cf 91) ;; ?\[
(setq cn "]"))
((eq cf 45) ;; ?\-
(setq cn "_"))
((eq cf 95) ;; ?\_
(setq cn "-"))
((eq cf 92) ;; ?\\
(setq cn "/"))
((eq cf 47) ;; ?\/
(setq cn "\\"))
(t (when (eq cf cn)
(setq cn (upcase cf)))))
(unless done
(delete-char 1)
(insert cn))))))

How do I get all paragraphs in Emacs Lisp?

I am defining a major mode that works on paragraphs of the following nature:
: Identifier
1. some text
2. ...
3. some more text
: New Identifier
: Another Identifier
some text
I want to write a defun called get-paragraphs that will return a list that looks like:
( ("Identifier", ("1. some text", "2. ...", "3. some more text")),
("New Identifier", ()),
("Another Identifier", ("some text"))
)
How do I go about cutting up the text like this in Emacs Lisp:
Is there a function to iterate through them (and subsequently chop them up to my liking)? Should I use regular expressions? Is there an easier way?
You should iterate over the buffer and collect your text (untested):
(defun get-paragraphs ()
(save-excursion
(goto-char (point-min))
(let ((ret '()))
(while (search-forward-regexp "^: " nil t)
(let ((header (buffer-substring-no-properties (point) (line-end-position)))
(body '()))
(forward-line)
(while (not (looking-at "^$"))
(push (buffer-substring-no-properties (point) (line-end-position)) body)
(forward-line))
(push (cons header (list (reverse body))) ret)))
(nreverse ret))))
Here, take this Lisp code:
(defun chopchop ()
(mapcar
(lambda (x)
(destructuring-bind (head &rest tail)
(split-string x "\n" t)
(list head tail)))
(split-string (buffer-substring-no-properties
(point-min)
(point-max)) "\n?: *" t)))

how to set 4 space indent in emacs

every time I add a new line, it would indent automatically but it indents 2 spaces, not 4 spaces.
Below is my .emacs snippet.
(defun make-vline-xpm (width height color &optional lor)
(let* ((w width)
(h height)
(s1 (concat "\"" (make-string w (string-to-char " ")) "\""))
(s2 (cond
((eq lor 0)
(concat "\"." (make-string (1- w) (string-to-char " ")) "\""))
((eq lor 1)
(concat "\"" (make-string (1- w) (string-to-char " ")) ".\""))
((null lor)
(concat "\"" (make-string (- (1- w)(/ (1- w) 2))(string-to-char " "))
"." (make-string (/ (1- w) 2)(string-to-char " ")) "\""))))
(sa (concat s1 ",\n" s2 ",\n")))
(eval `(concat "/* XPM */
static char * dot_vline_xpm[] = {
\"" (number-to-string w) " " (number-to-string h) " 2 1\",
\" c None\",
\". c " color "\",\n"
,#(mapcar (lambda(x) sa)
(make-list (1- (/ h 2)) 0))
s1 ",\n" s2 "};"
))))
(defvar indent-vline-img (make-vline-xpm 9 20 "#4D4D4D"))
(defun draw-indent-tab (beg end &optional color)
(if window-system
(set-text-properties
beg end
`(display (image
:type xpm
:data ,indent-vline-img
:pointer text
:ascent center
:mask (heuristic t))
rear-nonsticky (display)
fontified t))
(compose-region
beg end
(prog1 "|"
(set-text-properties beg end '(font-lock-face (:foreground "#4D4D4D"))))
'decompose-region)))
(defun draw-indent-vline ()
(interactive)
(save-excursion
(beginning-of-line)
(let* ((i (current-indentation))
(l (save-excursion
(count-lines (point)
(forward-list)))))
(while (> l 0)
(let* ((p1 (progn (move-to-column i)(point)))
(p2 (1+ p1)))
(if (and (eq (get-byte p1) 32)
(save-excursion
(skip-chars-backward " ")(bolp)))
(draw-indent-tab p1 p2))
nil)
(forward-line)
(setq l (1- l))))))
(defun indent-vline-lisp ()
(interactive)
(funcall
(lambda (x)
(font-lock-add-keywords
nil `((,x
(0 (draw-indent-vline))))))
"^[ \t]*[,`#'(]")
(defadvice delete-char (after indent-vline activate compile)
(save-excursion
(let* ((p (point))
(q (skip-chars-forward " "))
(x (progn (skip-chars-backward " ")(bolp))))
(if x
(remove-text-properties p (+ p q) '(display)))))))
(defun indent-vline ()
(interactive)
(funcall
(lambda (x)
(font-lock-add-keywords
nil `((,x
(0 (if (save-excursion
(skip-chars-backward " ")(bolp))
(let* ((p1 (point))
(p2 (1+ p1)))
(if (or (null (eq (get-byte p1) 32))
(get-text-property p1 'display))
nil
(draw-indent-tab p1 p2)
nil))))))))
" \\( \\)")
(defadvice delete-char (after indent-vline activate compile)
(save-excursion
(let* ((p (point))
(q (skip-chars-forward " "))
(x (progn (skip-chars-backward " ")(bolp))))
(if x
(remove-text-properties p (+ p q) '(display)))))))
I do not know lisp language. This .emscs is copied from others'. So my problem is how to set 4 space indent?
I have tried to add below to my .emacs, but it does not work.
(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(setq indent-line-function 'insert-tab)
How about using custom-set-variables:
(custom-set-variables
'(tab-width 4))

In-Place Word/Symbol Dabbrev Expand

Here's my extension to dabbrev-expand to support sub-string expansion.It works as expected, as far as I know. However I would find it even more useful if it supported in-symbol expansion similar to the behaviour of mdabbrev, which, by the way, is incomplete in terms of symbol-character and case-adjustment support. The pattern argument to dabbrev-substring-search, however, is only the pattern before point but for in-place expansions we need the pattern after point aswell. Why isn't this pattern available in hippie/dabbrev-expand and is there a preferred way to query it?
(defun dabbrev-substring-search (pattern &optional reverse limit syntax-context)
"Expand dabbrev substring. See:
http://www.emacswiki.org/cgi-bin/wiki/HippieExpand#toc5"
(let ((result ())
(regpat (cond ((not hippie-epxand-dabbrev-as-symbol)
(concat (regexp-quote pattern) W*))
;; ((eq (char-syntax (aref pattern 0)) ?_)
;; (concat (regexp-quote pattern)
;; "\\(\\sw\\|\\s_\\)*"))
(t
(concat "\\(?:"
Y<
"\\(" "\\(?:\\sw\\|\\s_\\)+" "\\)"
"\\(" (regexp-quote pattern) "\\)"
"\\(" "\\(?:\\sw\\|\\s_\\)*" "\\)"
Y>
"\\)"
"\\|"
"\\(?:"
Y<
"\\(" "\\(?:\\sw\\|\\s_\\)*" "\\)"
"\\(" (regexp-quote pattern) "\\)"
"\\(" "\\(?:\\sw\\|\\s_\\)+" "\\)"
Y>
"\\)"
)))))
(while (and (not result)
(if reverse
(re-search-backward regpat limit t)
(re-search-forward regpat limit t)))
(setq result (buffer-substring-no-properties (save-excursion
(goto-char (match-beginning 0))
;;(skip-syntax-backward "w_")
(point))
(match-end 0)))
(if (he-string-member result he-tried-table t)
(setq result nil))) ; ignore if bad prefix or already in table
(when nil
(when result
(let* ((p (point))
(end3 (match-end 3))
(beg2 (match-end 2))
(end2 (match-end 2))
(dummy (message "%s %s %s" end3 beg2 end2))
(beg (- end3 beg2)) ;begin offset from point
(end (- end3 end2))) ;end offset from point
(setq dabbrev-substring-match-region (cons beg end))
(hictx-generic (- p beg) (- p end) nil 'match 3))))
result))
;; Use: (dabbrev-substring-search "he")
(defun try-expand-dabbrev-substring-visible (old)
"Like `try-expand-dabbrev' but for visible part of buffer."
(interactive "P")
(let ((old-fun (symbol-function 'he-dabbrev-search)))
(fset 'he-dabbrev-search (symbol-function 'dabbrev-substring-search))
(unwind-protect (try-expand-dabbrev-visible old)
(fset 'he-dabbrev-search old-fun))))
(defun try-expand-dabbrev-substring (old)
"Like `try-expand-dabbrev' but for substring match."
(interactive "P")
(let ((old-fun (symbol-function 'he-dabbrev-search)))
(fset 'he-dabbrev-search (symbol-function 'dabbrev-substring-search))
(unwind-protect (try-expand-dabbrev old)
(fset 'he-dabbrev-search old-fun))))
(defun try-expand-dabbrev-substring-all-buffers (old)
"Like `try-expand-dabbrev-all-buffers' but for substring match."
(interactive "P")
(let ((old-fun (symbol-function 'he-dabbrev-search)))
(fset 'he-dabbrev-search (symbol-function 'dabbrev-substring-search))
(unwind-protect (try-expand-dabbrev-all-buffers old)
(fset 'he-dabbrev-search old-fun))))
which is activated for example using
(setq hippie-expand-try-functions-list
(append
'(
try-expand-dabbrev-substring-visible
try-expand-dabbrev-substring
try-expand-dabbrev-substring-all-buffers)))
This might or might not help. Like ordinary dabbrev, it works with the text before point, but candidate matching can be substring, regexp, or fuzzy (various kinds), in addition to prefix. Icicles - Dynamic Abbreviation