I am trying to set up a tempo-template that when called with a C-u prefix is to surround the region with the tags \begin{environment} and \end{environment} and insert the tag \item at the beginning of each line in the region. However it gives as 'save-excursion: Args out of range: 2247, 2312' error.
(require 'tempo)
(setq tempo-interactive t)
(tempo-define-template "env"
'("\\begin{" (p "Environment: " environment) "}" > n>
r> n>
"\\end{" (s environment) "}" > n
(save-excursion
(narrow-to-region start end)
(goto-char (point-min))
(while (re-search-forward "^" nil t) (replace-match "\\item " nil t))
(widen)
))
"env"
"Insert a LaTeX environment.")
(defun item (start end)
(interactive "r")
(save-excursion
(narrow-to-region start end)
(goto-char (point-min))
(while (re-search-forward "^" nil t) (replace-match "\\item " nil t))
(widen)
))
The item function by itself works fine on a region. I tried calling the elisp function item in the tempo-template:
(tempo-define-template "env"
'("\\begin{" (p "Environment: " environment) "}" > n>
r> n>
"\\end{" (s environment) "}" > n
(item point-min point-max)
)
"env"
"Insert a LaTeX environment.")
However, this gives a 'eval: Symbol's value as variable is void: point-min' error.
Any pointers to fix the problem are appreciated.
point-min and point-max are functions, so you should call them as in (item (point-min) (point-max)):
(tempo-define-template
"env"
'("\\begin{" (p "Environment: " environment) "}" > n>
r> n>
"\\end{" (s environment) "}" > n
(item (point-min) (point-max))) ; HERE
"env"
"Insert a LaTeX environment.")
#Deokhwan Kim: Thanks for looking into this. Using (item (point-min) (point-max)) in the template does the replacement over the entire buffer. With (item (region-beginning) (region-end)) the modified template now works:
(require 'tempo)
(setq tempo-interactive t)
(tempo-define-template
"list"
'("\\begin{" (p "List environment: " environment) "}" > n>
r> (item (region-beginning) (region-end))
"\\end{" (s environment) "}" > n>
)
"list"
"Insert a LaTeX list environment.")
(defun item (start end)
(interactive "r")
(save-excursion
(narrow-to-region start end)
(goto-char (point-min))
(while (re-search-forward "^[^\\]" (point-max) t) (replace-match "\\item " nil t))
(widen)
))
Related
I'm having trouble finding where cons has been defined in Clojurescript as it is not there in the ISeq protocol.
https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L616
Is it a compile time or runtime thing?
https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L3297
(defn cons
"Returns a new seq where x is the first element and coll is the rest."
[x coll]
(cond
(nil? coll) (List. nil x nil 1 nil)
(implements? ISeq coll) (Cons. nil x coll nil)
:default (Cons. nil x (seq coll) nil)))
https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L3237
(deftype Cons [meta first rest ^:mutable __hash]
ASeq
ISeq
(-first [coll] first)
(-rest [coll] (if (nil? rest) () rest)))
I started writing the code below for a homework from university which consist on parsing a json-string in Common Lisp. The main issue that I'm facing right now is to get the right substring\subsequence to continue with the recursive call and parse the rest of the string. Basically the main idea is to recursively check the whole string. Following the given syntax the input string should be:
1) "{\"nome\" : \"arturo\" , \"cognome\" : \"durone\" , \"età\" : \"22\" , \"corso\" : \"informatica\"}"
2) "{\"name\" : \"Zaphod\",\"heads\" : [[\"Head1\"], [\"Head2\"]]}"
3) "{\"name\" : \"Zaphod\",{property:value, property : [1,2,3] }
4) "[1,2,3]"
Basically I do remove any space and any \" from the string getting a clean string "{name:Zaphod,heads:[[Head1],[Head2]]}" , here I check the position of ':' and get the subsequence from 0 to ((position ":")-1), and the same for the second part, but the problem comes when I have to pass to the recursive call, since I don't know how to pass the right index of the string.
I tried to check the length of any element of the new list that the function gives me in output, but it doesn't work/help since the string is split and there not the space and \" chars from the initial input. Could you please help me to find out a way to parse the rest of the json-string following a recursive approach?
> main function
(defun j-obj (str)
(cond ((correct_form str)
`(json-obj-aux(revome_braces (remove_backslash(remove_space str)))))))`
> aux function that thru a recursive call analize the whole string
(defun json-obj-aux (str)
(cond ((= (length str) 0)nil)
((cons (aux_control str)nil))))
; (json-obj-aux (subseq (shorter str)(length (aux_control (shorter str)))
; (length (shorter str))))))))
> check the whole string , splitting once it finds ":"
(defun aux_control (str)
(cons (subseq str 0 (search ":" str))(check_type (subseq str (+ (search ":" str) 1) (length str)))))
(defun check_type (str)
(cond ((equal (subseq str 0 1) "{")(obj_c str))
((equal (subseq str 0 1) "[")(cons (obj_array (remove_braces str))nil))
(t (cons (subseq str 0 (search "," str))nil))))
(defun obj_c (str)
"{")
(defun obj_array (str)
(cond ((= 0 (length str))nil)
((null (search "," str))(cons (subseq str (+ (search "[" str)1)(- (length str)1))nil))
((and (null (search "[" str))(null (search "," str)))(cons str nil))
((null (search "[" str))(cons (subseq str 0 (search "," str))
(obj_array (subseq str (+ (search "," str) 1)))))
((cons (subseq str (+ (search "[" str) 1)(search "]" str))
(obj_array (subseq str (+ (search "," str) 1)))))))
(defun remove_space (str)
(cond ((= 0 (length str))nil)
((concatenate 'string (remove_aux str) (remove_space(subseq str 1))))))
(defun remove_aux (str)
(cond ((equal (subseq str 0 1) " ")"")
((concatenate 'string (subseq str 0 1) ""))))
(defun remove_backslash (str)
(cond ((= 0 (length str))nil)
((concatenate 'string (remove_slash str)(remove_backslash(subseq str 1))))))
(defun remove_slash (str)
(cond ((equal (subseq str 0 1) "\"")"")
((concatenate 'string (subseq str 0 1) ""))))
(defun remove_braces (str)
(subseq str 1 (- (length str) 1)))
(defun shorter (str)
(subseq str 1 (length str)))
This is what I get until now which is not completely wrong since I can parse parts of the json-string. What I can't really parse is the whole one cause I don't know how to pass the right index of the new subsequence:
CL-USER 1 > (j-obj "{\"name\" : \"Zaphod\",\"heads\" : [[\"Head1\"], [\"Head2\"]]}")
(("name" "Zaphod"))
CL-USER 2 > (j-obj "{\"heads\" : [[\"Head1\"], [\"Head2\"]]}")
(("heads" ("Head1" "Head2")))
The right output should be:
(("name" "Zaphod")("heads" ("Head1" "Head2")))
You should not remove characters from your input that help determining what is coming next. {name:Zaphod,heads:[[Head1],[Head2]]} is not clean, it is invalid JSON. All keys in JSON must be strings, all strings enclosed in "". Head1 is not a valid thing in JSON.
One way to do this cleanly is to first tokenize the string:
"{\"name\" : \"Zaphod\",\"heads\" : [[\"Head1\"], [\"Head2\"]]}"
yields
{
"name"
:
"Zaphod"
,
"heads"
:
[
[
"Head1"
]
,
[
"Head2"
]
]
}
The parse-json function then takes a look at the first token: if it is a string, it yields a string; if it is a number, it yields a number; if it is a boolean, it yields that boolean; … if it is a {, it calls parse-json-obj; if it is a [, it calls parse-json-array.
Parse-json-obj repeatedly calls parse-key-value until the next token is a }, not a ,.
Parse-key-value parses a string (error otherwise), then a :, then calls parse for the value.
You can keep track of where you are in the token list by returning the rest as a second value from each parse* function.
In Common Lisp, I'm using cl-json to output json format, but how can I output a false instead of null?
This is the set of utilities I use when I need to properly handle false with cl-json:
(defclass json-false ()
())
(defmethod json:encode-json ((object json-false) &optional stream)
(princ "false" stream)
nil)
(defvar *json-false* (make-instance 'json-false))
(defun json-bool (val)
(if val t *json-false*))
(defun json-bool-handler (token)
(or (string= token "true")
(and (string= token "false") *json-false*)))
(defmacro preserving-json-boolean (opts &body body)
(declare (ignore opts))
`(let ((json:*boolean-handler* #'json-bool-handler))
,#body))
Now, to encode a literal false, I would way
* (json:encode-json-to-string `((foo . nil) (bar . t) (baz . ,*json-false*)))
"{\"foo\":null,\"bar\":true,\"baz\":false}"
Or, to encode a LISP boolean into a json boolean:
* (let ((something nil))
(json:encode-json-to-string `((bool . ,(json-bool something)))))
"{\"bool\":false}"
Or, to read in JSON data preserving the distinction between null and false:
* (preserving-json-boolean ()
(json:decode-json-from-string "{\"foo\":null,\"bar\":true,\"baz\":false}"))
((:FOO) (:BAR . T) (:BAZ . #<JSON-FALSE #x21029D2E4D>))
Of course, some care must be taken when reading in data like that;
* (when (cdr (assoc :baz *))
'yep)
YEP
How to write a function where whenever a variable is found, it returns t (in order to allow a loop):
(setq x 1)
(while ("backward search for regexp "%x" equals true") ;where x is variable
(setq x (+ x 1))
(insert (concat "%" (int-to-string x)))
)
Example: If %1 (x=1) is found, it will add 1 to x. If %2 (x=2) is found, it will add 1 to x.
Let's say %3 is not found in a backward search, the while loop stops and "%" + "3" is inserted (%3).
I just don't understand the how to return true on a backward-search.
search-backward takes an optional third argument which, when non-nil, tells it to return nil in case the search was unsuccessful:
(setq x 1)
(while (search-backward (format "%%%d" x) nil t)
(setq x (1+ x)))
(insert (format "%%%d" x))
Now, if I try to understand what you really want to do (something like inserting at point the first %d string which doesn't appear before), then you might want to wrap the search inside a save-excursion form to avoid moving the point:
(setq x 1)
(while (save-excursion (search-backward (format "%%%d" x) nil t))
(setq x (1+ x)))
(insert (format "%%%d" x))
With help from Francesco
(defun Navi-insert-question ()
(interactive)
(setq x 1)
(while (save-excursion
(search-backward (concat comment-start " Question: " (int-to-string x)) nil t))
(setq x (+ 1 x)))
(insert (concat comment-start " Question: " (int-to-string x))))
It now results in being able to insert in R, for instance: "# Question: 1", when it exists above in the buffer it will insert "# Question: 2".
I am writing a function to uncomment regardless of mode. I want to delete all comment characters at the beginning of a line.
How do I make the snippet below loop until the following character is not equal to comment-start? (so basically have this "if" go on and on and on until following-char is not equal to comment-start anymore)
(if (string= (byte-to-string (following-char)) comment-start)
(progn (delete-forward-char 1)
(when (string= (byte-to-string (following-char)) " ")
(delete-forward-char 1))))
A while loop was easier than I thought:
(defun uncomment-mode-specific ()
"Uncomment region OR uncomment beginning of line comment OR uncomment end"
(interactive)
(if (region-active-p)
(uncomment-region (region-beginning) (region-end))
(back-to-indentation))
(setq scvar 0)
(setq scskipvar 0)
(while (= scvar 0)
(if (string= (byte-to-string (following-char)) comment-start)
(progn (delete-forward-char 1)
(when (string= (byte-to-string (following-char)) " ")
(delete-forward-char 1))
(setq scskipvar 1))
(setq scvar 1)))
(if (= scskipvar 0)
(progn (search-forward comment-start nil t)
(left-char 1)
(kill-line))
)
)