elisp - How to copy lines from a buffer effectively - elisp

I want to use elisp to copy lines from a buffer. for example: copy line 100 to 200 text to another buffer.
Should I select the region (goto-line) then copy it? just like what we do with keyboard? Some post say do not use goto-line in elisp code. I don't know what's effective way to do it.

Here's a function copy-lines-from-buffer that's similar to copy-to-buffer except that it works with line numbers instead of points, and unlike copy-to-buffer it does not erase the current contents of the target buffer:
(defun copy-lines-from-buffer (buffer start-line end-line)
"Copy the text from START-LINE to END-LINE from BUFFER.
Insert it into the current buffer."
(interactive "*bSource buffer: \nnStart line: \nnEnd line: ")
(let ((f #'(lambda (n) (goto-char (point-min))
(forward-line n)
(point))))
(apply 'insert-buffer-substring buffer
(with-current-buffer buffer
(list (funcall f start-line) (funcall f end-line))))))
The copy-lines-from-buffer function takes either a buffer or buffer name as its first argument, the start line number as its second argument, and the end line number as its third. It creates a local helper function f that returns point at the beginning of line n of the current buffer, and it calls f twice with the current buffer set to buffer to create a list consisting of the starting point and ending point of the desired buffer contents. It then uses apply to invoke insert-buffer-substring with buffer and the buffer contents start and end points as arguments.
Call copy-lines-from-buffer from the point in your buffer where you want the contents to be inserted. The contents of the start line are included in the copied content, but the contents of the end line are not included.

Related

Counting blocks in a specific location (autolisp)

So I'm making a simple function in autolisp to count the number of a specific block in a drawing, and it looks like this:
(defun c:contarblocos()
(setq ss (ssget "x" ' ((0. "INSERT") (2. "Nome do bloco"))))
(setq count (sslength ss))
(alert(strcat "Total de blocos no desenho: " (itoa count)))
)
Now, what I really want is to count the number of blocks in a specific area, defined by the user. In other words, the user will call the function, and then the function will ask for a specific area, where it will look for the specific block and count them, not counting any blocks from outside the selected area.
Rather than using the x mode string of the ssget function (which searches the entire drawing database for all entities which fulfil the criteria of the filter list argument), simply omit this argument to permit the user to make a selection using any valid selection method, e.g.:
(defun c:contarblocos ( / sel )
(if (setq sel (ssget '((0 . "INSERT") (2 . "Nome do bloco"))))
(alert (strcat "Total de blocos no desenho: " (itoa (sslength sel))))
)
(princ)
)
There are a few other issues with your current code:
Always declare the variables whose scope is local to your function: in my above example, you will note that the sel symbol is declared in the variable list within the defun expression. For more information on why this is important, you may wish to refer to my tutorial here.
You should test whether ssget returns a valid selection set before calling the sslength function to obtain the number of items in the set, since (sslength nil) will error. You will see that I use an if statement in my code to accomplish this.
The ssget filter list argument should be an association list of dotted pairs, and as such, there should be a space between the key and the value in each list item, hence this:
(0. "INSERT")
Should become:
(0 . "INSERT")
You should include a final (princ) or (prin1) expression within the defun expression so that the function returns a null symbol to the command line, rather than returning the value returned by the last evaluated expression (i.e. the alert expression, which will return nil). Including a (princ) expression per my example will ensure that the function exits 'cleanly'.

Filtering an expression output with regexp

The bad code of main is (string-match "module" (help uri-path)) that returns an error
scheme#(guile-user) [5]> (string-match "module" (help uri-path))
`uri-path' is an object in the (web uri) module.
- Special Form: uri-path
While compiling expression:
Syntax error:
unknown file:9:23: sequence of zero expressions in form (begin)
scheme#(guile-user) [5]>
What I am trying to reach, is displaying only one line of help function output. How to fix it?
Use procedure-documentation to get the documentation of a procedure as a string.
scheme#(guile-user)> (help cons)
`cons' is a procedure in the (ice-9 safe-r5rs) module.
- Scheme Procedure: cons x y
Return a newly allocated pair whose car is X and whose cdr is Y.
The pair is guaranteed to be different (in the sense of `eq?') from
every previously existing object.
scheme#(guile-user)> (procedure-documentation cons)
$6 = "- Scheme Procedure: cons x y\n Return a newly allocated pair whose car is X and whose cdr is Y.\n The pair is guaranteed to be different (in the sense of `eq?') from\n every previously existing object."

Completion for frame local variables from backtrace

I'm trying to add completion at point for frame-local variables from backtrace-frames during invocations of read--expression by debugger-eval-expression or edebug-eval-expression.
I constructed the following completion table to add frame-local variables to the already available table for local elisp variables,
;; completion table for locals in current frame
(defvar my-backtrace-locals-completion-table
(completion-table-in-turn
(completion-table-dynamic
(lambda (_string)
(when-let* ((idx (backtrace-get-index)) ;backtrace.el
(frame (nth idx backtrace-frames)))
(backtrace-frame-locals frame)))
'do-switch-buffer)
elisp--local-variables-completion-table)) ;elisp-mode.el
which seems to work fine, eg. to reproduce
(1) evaluate
;; debug-on-error = t
(let ((my-local-var '(1 2))) (mapcan #'car this-local-var))
(2) from debugger's second frame, evaluate with eval-expression
(funcall my-backtrace-locals-completion-table "my-" nil t)
returns expected ("my-local-var").
The problem is following the above steps, but calling instead calling debugger-eval-expression doesn't work. The environment where the table is evaluated isn't finding a backtrace-frame (with or without do-switch-buffer).
How can I define the table to be evaluated in the proper buffer?
emacs v27.0.50
The completion table above doesn't quite return the expected candidates for debugger-eval-expression. The environment where the expression is evaluated has locals from frames higher than, but not including, the one at point in the Backtrace buffer.
So, the available locals should be only those from higher frames, eg.
(eval-when-compile (require 'dash))
(defvar my-backtrace-locals-completion-table
(completion-table-dynamic
(lambda (_string)
(when backtrace-frames
(--mapcat
(-some->> (backtrace-frame-locals it) (--map (car it)))
(nthcdr (1+ (backtrace-get-index)) backtrace-frames))))
'do-switch-buffer))
Then, redefining debugger-eval-expression's interactive spec to use the new locals table in place of the normal elisp table provides the correct completions (passing the 'do-switch-buffer arg completion-table-dynamic to find completions in the original buffer).
(defun my-backtrace#eval (orig-fn exp &optional nframe)
(interactive
(let ((elisp--local-variables-completion-table
my-backtrace-locals-completion-table))
(list (read--expression "[my] Eval in stack frame: "))))
(apply orig-fn (list exp nframe)))
(advice-add 'debugger-eval-expression :around #'my-backtrace#eval)

In Clojurescript, how do I pass a collection's elements as arguments to a variable arity Javascript function?

This writes to console the way I would expect:
(.log js/console "hi" "there")
The output is
hi there
This, however, just writes a big mess to the console:
(defn log-it [& args] (.log js/console args))
(log-it "hello" "there")
The output is:
c…s.c…e.IndexedSeq {arr: Array[2], i: 0, meta: null, cljs$lang$protocol_mask$partition0$: 166592766, cljs$lang$protocol_mask$partition1$: 8192}
This also does NOT work:
(apply .log js/console ["hi" "there"])
Is there a way to pass the vector's elements into the .log function?
Do I have to write a macro to concat the vector on to '(.log js/console)?
The problem here is that you're trying to log the value of args (which is a Clojure IndexedSeq) rather than passing the values in the seq as individual arguments. In this case you need to use apply (or convert that sequence to a native data structure).
The reason your other example doesn't work should become clear if you look at the signature for apply.
(apply f args)
It expects the first argument to be the function you want to invoke, but here, the first argument is .log.
(apply .log js/console ["hi" "there"])
Remember that .log js/console is the syntax for invoking the log method on console. Instead, we want to get a reference to the console.log function.
(apply (.-log js/console) args)
We're using .-log to read the .log property, rather than call it as a method. Then we pass that along with our args sequence.
So instead, you can define the original function as:
(defn log-it
[& args]
(apply (.-log js/console) args))
Or if you want to get a little bit smarter.
(def log-it (partial (.-log js/console)))

How can I tell emacs how the arguments to my elisp function should be indented?

I have written function (actually a macro, but whatever) that works similarly to progn. How can I tell emacs that this function should be indented in the same way as progn?
This should do it
(put 'myfunc 'lisp-indent-function 0)
Documentation for lisp-indent-function (found by C-h f lisp-indent-function RET):
lisp-indent-function is a compiled Lisp function in `lisp-mode.el'.
(lisp-indent-function indent-point state)
This function is the normal value of the variable
`lisp-indent-function`. It is used when indenting a line within
a function call, to see if the called function says anything
special about how to indent the line.
indent-point is the position where the user typed TAB, or
equivalent. Point is located at the point to indent under
(for default indentation); state is the `parse-partial-sexp`
state for that position.
If the current line is in a call to a Lisp function which has
a non-nil property `lisp-indent-function`, that specifies how
to do the indentation. The property value can be:
* `defun`, meaning indent `defun`-style;
* an integer N, meaning indent the first N arguments specially
like ordinary function arguments and then indent any further
arguments like a body;
* a function to call just as this function was called. If that
function returns nil, that means it doesn't specify
the indentation.
This function also returns nil meaning don't specify the
indentation.
As it's "actually a macro":
C-hig (elisp) Indenting Macros RET
In this instance:
(defmacro my-macro (&rest body)
"Does things"
(declare (indent defun))
`(progn ,#body))
(my-macro
(message "foo")
(message "bar"))

Resources