How to copy a string and paste a substring in Emacs? - emacs

Found this on the interwebs:
(defun clipboard/set (astring)
"Copy a string to clipboard"
(with-temp-buffer
(insert astring)
(clipboard-kill-region (point-min) (point-max))))
I want to make it interactive, run the string through substring, and then copy it to the clipboard
(defun clipboard/set (astring)
"Copy a string to clipboard"
(interactive)
(let (bstring (substring astring -11)))
(with-temp-buffer
(insert bstring)
(clipboard-kill-region (point-min) (point-max))))
How would one do this?

You need to tell interactive how to populate the arguments:
(interactive "sAstring: ")
Also, the syntax of let is different, it starts with a list of lists of variables and values, i.e.
(let ((bstring (substring astring -11)))
; ^^
i.e.
(defun clipboard/set (astring)
"Copy a string to clipboard"
(interactive "sAstring: ")
(let ((bstring (substring astring -11)))
(with-temp-buffer
(insert bstring)
(clipboard-kill-region (point-min) (point-max)))))
and close it at the very end.

Related

Split lines of current paragraph in Emacs

I want to add a function (para2lines) to Emacs by which I can split the current paragraph into its sentences and print them line by line in a separate buffer. Following is code in Racket/Scheme:
(define (p2l paraString)
(define lst (string-split paraString ". "))
(for ((i lst))
(displayln i)))
Testing:
(p2l "This is a test. For checking only. Only three lines.")
Output:
This is a test.
For checking only.
Only three lines.
In Emacs Lisp, I could manage following code:
(defun pl (ss)
(interactive)
(let ((lst (split-string (ss))))
(while lst
(print (pop lst)))))
But I do not know how to get the text from the paragraph with current position. How can I correct this function?
Edit: basically, I want to read it as separate lines but want to save it as paragraph.
Here's an example that might help you on your way. It will do your conversion to the current paragraph (i.e. where the cursor is positioned), rather than to a new buffer. You could modify this to pass a string to your function if that's what you require.
(defun p2l ()
"Format current paragraph into single lines."
(interactive "*")
(save-excursion
(forward-paragraph)
(let ((foo (point)))
(backward-paragraph)
(replace-regexp "\n" " " nil (1+ (point)) foo)
(backward-paragraph)
(replace-regexp "\\. ?" ".\n" nil (point) foo))))
I would just run Emacs commands or write a macro to convert a paragraph to single-sentence lines, but maybe you are really just wanting to read wrapped paragraphs as lines, thus the need to have an Emacs command.
Here's something that will grab the current paragraph, insert a new buffer *Lines*, and then convert sentences to lines.
(defun para-lines ()
"Split sentences of paragraph to lines in new buffer."
(interactive)
;; Move the paragraph to a new buffer.
(let ((b (generate-new-buffer "*Lines*")))
(with-output-to-temp-buffer b
(let ((beg (save-excursion (forward-paragraph -1) (point)))
(end (save-excursion (forward-paragraph +1) (point))))
(princ (buffer-substring-no-properties beg end))))
;; Switch to new buffer
(with-current-buffer b
;; Since the name starts with "*", shut off Help Mode
(fundamental-mode)
;; Make sure buffer is writable
(setq buffer-read-only nil)
;; From the start of the buffer
(goto-char (point-min))
;; While not at the end of the buffer
(while (< (point) (point-max))
(forward-sentence 1)
;; Delete spaces between sentences before making new new line
(delete-horizontal-space)
;; Don't add a new line, if already at the end of the line
(unless (= (line-end-position) (point))
(newline))))))
To avoid using forward-sentence, and just use a regular expression, use re-search-forward. For instance, to match semi-colons as well as periods.
(defun para-lines ()
"Split sentences of paragraph to lines in new buffer."
(interactive)
;; Move the paragraph to a new buffer.
(let ((b (generate-new-buffer "*Lines*")))
(with-output-to-temp-buffer b
(let ((beg (save-excursion (forward-paragraph -1) (point)))
(end (save-excursion (forward-paragraph +1) (point))))
(princ (buffer-substring-no-properties beg end))))
;; Switch to new buffer
(with-current-buffer b
;; Since the name starts with "*", shut off Help Mode
(fundamental-mode)
;; Make sure buffer is writable
(setq buffer-read-only nil)
;; From the start of the buffer
(goto-char (point-min))
;; While not at the end of the buffer
(while (< (point) (point-max))
(re-search-forward "[.;]\\s-+" nil t)
;; Delete spaces between sentences before making new new line
(delete-horizontal-space)
;; Don't add a new line, if already at the end of the line
(unless (= (line-end-position) (point))
(newline))))))

Emacs: select quoted string as one operation

In programming we ofter have a task of selecting text between quotes. Suppose, we have the following PHP code:
lwt_shared_save_conditions_to_session($conditions, "bundles_listing"■);
The cursor position is shown with black square. And we want to select and copy the text "bundles_listing" into the clipboard. I created the following function:
(defun select-quoted-text ()
(interactive)
(search-backward "\"")
(forward-char 1)
(cua-set-mark)
(backward-char 1)
(search-backward "\"")
(kill-ring-save (region-beginning) (region-end))
)
It will select the text between quotes.
How can I do the following:
1.Fold this code into 1 function call:
(forward-char 1)
(cua-set-mark)
(backward-char 1)
Select text both between single ' and double " quotes.
Try this:
(defun copy-quoted ()
"Copy current string into kill-ring.
The point can be anywhere in the string."
(interactive)
(let ((beg (or (nth 8 (syntax-ppss))
(and (memq (char-after (point))
'(?\" ?\'))
(point))))
end)
(when beg
(setq end
(save-excursion
(goto-char beg)
(forward-sexp)
(point)))
(kill-ring-save beg end))))
Here's how I'd do it interactively (rather than defining a function for it):
C-SPC C-M-b M-w
That runs the following commands:
set-mark-command
backward-sexp
kill-ring-save

Has anyone used elisp as a script language? [duplicate]

In Python, you might do something like
fout = open('out','w')
fin = open('in')
for line in fin:
fout.write(process(line)+"\n")
fin.close()
fout.close()
(I think it would be similar in many other languages as well).
In Emacs Lisp, would you do something like
(find-file 'out')
(setq fout (current-buffer)
(find-file 'in')
(setq fin (current-buffer)
(while moreLines
(setq begin (point))
(move-end-of-line 1)
(setq line (buffer-substring-no-properties begin (point))
;; maybe
(print (process line) fout)
;; or
(save-excursion
(set-buffer fout)
(insert (process line)))
(setq moreLines (= 0 (forward-line 1))))
(kill-buffer fin)
(kill-buffer fout)
which I got inspiration (and code) from Emacs Lisp: Process a File line-by-line. Or should I try something entirely different? And how to remove the "" from the print statement?
If you actually want batch processing of stdin and sending the result to stdout, you can use the --script command line option to Emacs, which will enable you to write code that reads from stdin and writes to stdout and stderr.
Here is an example program which is like cat, except that it reverses each line:
#!/usr/local/bin/emacs --script
;;-*- mode: emacs-lisp;-*-
(defun process (string)
"just reverse the string"
(concat (nreverse (string-to-list string))))
(condition-case nil
(let (line)
;; commented out b/c not relevant for `cat`, but potentially useful
;; (princ "argv is ")
;; (princ argv)
;; (princ "\n")
;; (princ "command-line-args is" )
;; (princ command-line-args)
;; (princ "\n")
(while (setq line (read-from-minibuffer ""))
(princ (process line))
(princ "\n")))
(error nil))
Now, if you had a file named stuff.txt which contained
abcd
1234
xyz
And you invoked the shell script written above like so (assuming it is named rcat):
rcat < stuff.txt
you will see the following printed to stdout:
dcba
4321
zyx
So, contrary to popular belief, you can actually do batch file processing on stdin and not actually have to read the entire file in at once.
Here's what I came up with. Looks a lot more idiomatic to me:
(with-temp-buffer
(let ((dest-buffer (current-buffer)))
(with-temp-buffer
(insert-file-contents "/path/to/source/file")
(while (search-forward-regexp ".*\n\\|.+" nil t)
(let ((line (match-string 0)))
(with-current-buffer dest-buffer
(insert (process line)))))))
(write-file "/path/to/dest/file" nil))
Emacs Lisp is not suitable for processing file-streams. The whole file must be read at once:
(defun my-line-fun (line)
(concat "prefix: " line))
(let* ((in-file "in")
(out-file "out")
(lines (with-temp-buffer
(insert-file-contents in-file)
(split-string (buffer-string) "\n\r?"))))
(with-temp-file out-file
(mapconcat 'my-line-fun lines "\n")))

Word wrap for Emacs print buffer to PDF

I use this function for printing a buffer's content to PDF
(from my .emacs file:)
(defun print-to-pdf ()
(interactive)
(ps-spool-buffer-with-faces)
(switch-to-buffer "*PostScript*")
(write-file "/tmp/tmp.ps")
(kill-buffer "tmp.ps")
(setq cmd (concat "ps2pdf14 /tmp/tmp.ps /home/user/" (buffer-name) ".pdf"))
(shell-command cmd)
(shell-command "rm /tmp/tmp.ps")
(message (concat "Saved to: /home/user/" (buffer-name) ".pdf"))
)
I cannot, however, find a way to enable or apply the visual-line minor mode to the PostScript buffer before it gets written to disk so to enable word wrap in the output.
The problem with getting visual line mode to be respected is that it inserts "soft newlines" (which get ignored by the PS renderer). A solution is to replace these with hard newlines. The code below does what you want, I think. Note that we call harden-newlines in a temporary buffer so as not to mess up the current document. Also, I've changed the output destination to always land in /tmp/print.pdf. It seems... unwise to overwrite documents in your /home without any sort of warning! You can always move the PDF afterwards.
Anyway, here you go. Is this what you wanted?
(defun harden-newlines ()
(interactive)
"Make all the newlines in the buffer hard."
(save-excursion
(goto-char (point-min))
(while (search-forward "\n" nil t)
(backward-char)
(put-text-property (point) (1+ (point)) 'hard t)
(forward-char))))
(defun spool-buffer-given-name (name)
(load "ps-print")
(let ((tmp ps-left-header))
(unwind-protect
(progn
(setq ps-left-header
(list (lambda () name) 'ps-header-dirpart))
(ps-spool-buffer-with-faces))
(setf ps-left-header tmp))))
(defun print-to-pdf ()
"Print the current file to /tmp/print.pdf"
(interactive)
(let ((wbuf (generate-new-buffer "*Wrapped*"))
(sbuf (current-buffer)))
(jit-lock-fontify-now)
(save-current-buffer
(set-buffer wbuf)
(insert-buffer sbuf)
(longlines-mode t)
(harden-newlines)
(spool-buffer-given-name (buffer-name sbuf))
(kill-buffer wbuf)
(switch-to-buffer "*PostScript*")
(write-file "/tmp/print.ps")
(kill-buffer (current-buffer)))
(call-process "ps2pdf14" nil nil nil
"/tmp/print.ps" "/tmp/print.pdf")
(delete-file "/tmp/print.ps")
(message "PDF saved to /tmp/print.pdf")))

Wrap selection in Open/Close Tag like TextMate?

In TextMate, one can use ctrl-shift-w to wrap text in an Open/Close tag and ctrl-shift-cmd-w to wrap each line in a region in Open/Close tags. How can I implement this same functionality in Emacs using emacs lisp?
emacs
becomes
<p>emacs</p>
And ...
emacs
textmate
vi
becomes
<li>emacs</li>
<li>textmate</li>
<li>vi</li>
This answer gives you a solution for wrapping the region (once you modify it to use angle brackets).
This routine will prompt you for the tag to use, and should tag every line in the region with an open/close tag of that type:
(defun my-tag-lines (b e tag)
"'tag' every line in the region with a tag"
(interactive "r\nMTag for line: ")
(save-restriction
(narrow-to-region b e)
(save-excursion
(goto-char (point-min))
(while (< (point) (point-max))
(beginning-of-line)
(insert (format "<%s>" tag))
(end-of-line)
(insert (format "</%s>" tag))
(forward-line 1)))))
*Note: *If you wanted the tag to always be li, then remove the tag argument, remove the text \nMTag for line: from the call to interactive, and update the insert calls to just insert the "<li\>" as you would expect.
For sgml-mode deratives, mark region to tagify, type M-x sgml-tag, and type the tag name you like to use (press TAB to get list of available HTML elements). Altough, this method does not allow you to tagify each line in a region, you can work around this by recording a keyboard macro.
yasnippet is a particularly good implementation of Textmate's snippet syntax for Emacs. With that you can import all of Textmate's snippets. If you install it then, this snippet that I wrote should do what you want:
(defun wrap-region-or-point-with-html-tag (start end)
"Wraps the selected text or the point with a tag"
(interactive "r")
(let (string)
(if mark-active
(list (setq string (buffer-substring start end))
(delete-region start end)))
(yas/expand-snippet (point)
(point)
(concat "<${1:p}>" string "$0</${1:$(replace-regexp-in-string \" .*\" \"\" text)}>"))))
(global-set-key (kbd "C-W") 'wrap-region-or-point-with-html-tag)
EDIT: (Okay this is my last attempt at fixing this. It is exactly like Textmate's version. It even ignores characters after a space in the end tag)
Sorry I misread your question. This function should edit each line in the region.
(defun wrap-lines-in-region-with-html-tag (start end)
"Wraps the selected text or the point with a tag"
(interactive "r")
(let (string)
(if mark-active
(list (setq string (buffer-substring start end))
(delete-region start end)))
(yas/expand-snippet
(replace-regexp-in-string "\\(<$1>\\).*\\'" "<${1:p}>"
(mapconcat
(lambda (line) (format "%s" line))
(mapcar
(lambda (match) (concat "<$1>" match "</${1:$(replace-regexp-in-string \" .*\" \"\" text)}>"))
(split-string string "[\r\n]")) "\n") t nil 1) (point) (point))))
This variant on Trey's answer will also indent the html correctly.
(defun wrap-lines-region-html (b e tag)
"'tag' every line in the region with a tag"
(interactive "r\nMTag for line: ")
(setq p (point-marker))
(save-excursion
(goto-char b)
(while (< (point) p)
(beginning-of-line)
(indent-according-to-mode)
(insert (format "<%s>" tag))
(end-of-line)
(insert (format "</%s>" tag))
(forward-line 1))))