Emacs lisp semicolon character? - emacs

It's a silly question, really.
I want to do
(position ?; "This is a test; or is it?")
Unfortunately, the font-lock is regex based,
so it highlights a part of the code as a comment.
What's the best way to handle this? At the moment, I've got either
(defconst semicolon (aref ";" 0))
(position semicolon "This is a test; or is it?")
or
(position 59 "This is a test; or is it?")

You should escape the semicolon with a backslash:
(position ?\; "This is a test; or is it?")

Related

How can I use Lisp subseq using colon (or other non-alphanumeric characters)?

I need to extract a substring from a string; the substring is enclosed by ":" and ";". E.g.
:substring;
But with Lisp (SBCL), I'm having trouble extracting the substring. When I run:
(subseq "8.I:123;" : ;)
I get:
#<THREAD "main thread" RUNNING {1000510083}>:
illegal terminating character after a colon: #\
Stream: #<SYNONYM-STREAM :SYMBOL SB-SYS:*STDIN* {1000025923}>
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-IMPL::READ-TOKEN #<SYNONYM-STREAM :SYMBOL SB-SYS:*STDIN* {1000025923}> #\:)
I've tried preceding the colon and semicolon with \ but that throws a different error. Can anyone advise? Thanks in advance for the help!
As you can see in docs for subseq, start and end are bounding index designators and they can be either integer or nil.
#\: and #\; are characters, so you can't use them, but you can use the function position to find the first index of each character and use these indices as arguments for subseq. You have to check that both indices exist and the second one is bigger than the first one:
(let* ((string "8.I:123;")
(pos1 (position #\: string))
(pos2 (position #\; string)))
(when (and pos1 pos2 (> pos2 pos1))
(subseq string
(1+ pos1)
pos2)))
=> "123"
This is a little bit cumbersome, so I suggest you to use some regex library. The following example was created with CL-PPCRE:
(load "~/quicklisp/setup.lisp")
(ql:quickload :cl-ppcre)
> (cl-ppcre:all-matches-as-strings "(?<=:)([^;]*)(?=;)" "8.I:123;:aa;")
("123" "aa")

Checking user input in Racket

I am getting an input from a user for a tex-field% in racket which would look something like this:
open button a = fwd; button b = xxx; button s = xxx; close
I have verified that it does contain open and close at beginning and end respectively. But now i need to store each of the substrings based on the semicolons to check them for semicolons at the end, among other things. For example, in the example above it should store 3 substrings in a vector/list (whichever is easier). It would be stored as:
button a = fwd;
button b = xxx;
button s = xxx;
;input is the name of the string the user enters
(define vec (apply vector (string-split input)))
(define vecaslist(vector->list vec))
(define removedopen (cdr vecaslist))
(define withoutopenandclose (reverse(cdr(reverse removedopen))))
(define stringwithoutopen (string-replace input "open " ""))
(define stringtoderivate (string-replace stringwithoutopen " close" ""))
(define tempvec (apply vector (string-split stringtoderivate ";" #:trim? #f #:repeat? #t)))
Attempted to split it by semicolons and place in a vector, but it removes the semicolons. When i do print the length of the vector it correctly shows 3 though, but i would like to keep the semicolons for now.
You can use string-split with a regular expression separator, as follows:
(string-split input #rx"(open | close)|(?<=;).")
which will output the list:
'("button a = fwd;" "button b = xxx;" "button s = xxx;")
To break down the regular expression:
(exp) matches any sub-expression "exp". Hence, (open ) matches the sub-expression "open " in input. Similarly with ( close), matching " close".
(?<=exp) does a positive look-behind, matching if "exp" matches preceding.
. matches anything, such as whitespace, characters etc.
| matches either the expression that comes before it, or after it, trying left first.

When do variables output properly in skeletons functions?

I'm trying to write a skeleton-function to output expressions in a loop. Out of a loop I can do,
(define-skeleton test
""
> "a")
When I evaluate this function it outputs "a" into the working buffer as desired. However, I'm having issues when inserting this into a loop. I now have,
(define-skeleton test
"A test skeleton"
(let ((i 1))
(while (< i 5)
>"a"
(setq i (1+ i)))))
I would expect this to output "aaaaa". However, instead nothing is outputted into the working buffer in this case. What is happening when I insert the loop?
The > somestring skeleton dsl does not work inside lisp forms.
You can however concatenate the string inside a loop:
(define-skeleton barbaz
""
""
(let ((s ""))
(dotimes (i 5)
(setq s (concat s "a")))
s)
)
My understanding is that code such as
> "a"
only works at the first nesting level inside a skeleton.
[EDIT] Regarding your question
What is happening when I insert the loop?
The return value of the let form (that is, the return value of the while form)is inserted. I do not know why it does not raise an error when evaluating > "a", but the return value of a while form is nil, so nothing is inserted.
I do agree that there's not much point using define-skeleton if you're going to need an (insert function within the skeleton.
This is also a rather trivial example to be using define-skeleton.
That said, they are often easier to read than a defun and useful when you want to create a function that inserts text (and optionally, takes input).
For example you may wish to have a different character repeated a set no. of times... Below, str refers to the argument supplied with the function (usually a string) and v1, v2 are the default names for local variables in a skeleton. Thus:
(define-skeleton s2 ""
nil ; don't prompt for value of 'str'
'(set 'v1 (make-string 5 (string-to-char str)))
\n v1 \n \n)
Below, calling the function leads to a newline, the string, then leaves the cursor at the position indicated by the square brackets [].
(s2 "a")
aaaaa
[]

Trying to define comments for SPSS in syntax table

I'm trying to modify spss.el to provide accurate fontification for SPSS comments. Below is a summary of how SPSS's syntax highlights and treats comments:
* = an asterisk starts commment at beginning of line
\n\n = two new lines end comments
.\n = period + newline also ends comment
/* = slash and star starts comment, and is ended with a single new line
*/ ends a comment only if on the same line as a /*
So far my syntax table reads:
(let ((spss-mode-syntax-table (make-syntax-table)))
(modify-syntax-entry ?* "<" spss-mode-syntax-table)
(modify-syntax-entry ?. ". 3" spss-mode-syntax-table)
(modify-syntax-entry ?\n "- 34" spss-mode-syntax-table)
(modify-syntax-entry ?' "\"" spss-mode-syntax-table)
(modify-syntax-entry ?\\ "# " spss-mode-syntax-table)
spss-mode-syntax-table)
This for the most part works, except that the asterisk only functions as a commment delimiter when it's at the beginning of a line. Is there a way to denote that the asterisk is a comment delimiter only at the line start?
Thank you for reading!
For the /* ... */ part, you can use
(modify-syntax-entry ?/ ". 14" st)
(modify-syntax-entry ?* ". 23" st)
(modify-syntax-entry ?\n ">" st)
But for the * ... \n\n, you need a different comment style and since it reuses the same chars * and \n as the other comment style, you can't use simple syntax-table settings to explain it to Emacs. Instead, you'll need to use a syntax-propertize-function which will place a "< b" syntax on a * at beginning of line and a "> b" syntax on the \n of \n\n. E.g.
(set (make-local-variable 'syntax-propertize-function)
(syntax-propertize-rules
("^\\(\\*\\)" (1 "< b"))
("\n\\(\n\\)" (1 "> b"))
("\\(\\.\\)\n" (1 "> b"))))

How to use case and read-event with down-mouse-1

I have a function that uses (case (read-event) . . .) -- I have been unable to get down-mouse-1 to equal an integer for the duration of the function. The following is an example where down-mouse-1 yields a result of Try again instead of Hello world. All of the following examples work, except for down-mouse-1: ('f12 516); (?\s-k 517); ('f3 518); ('C-tab 519); ('C-M-s-right 520); (?m 522).
(let* (
(test (case (read-event)
('down-mouse-1 9999))))
(cond
((eq test 9999)
(message "Hello world."))
(t (message "Try again."))))
read-event never returns down-mouse-1. For a mouse click, the first event it will return will look like (down-mouse-1 ...). So you could do:
(pcase (read-event)
(`(down-mouse-1 . ,_) 9999))
Note that in my experience, 99% of the uses of read-event would be better rewritten some other way.
Not clear to me what you are trying to do. But you should not quote the keys in a case clause. E.g, use down-mouse-1, not 'down-mouse-1.