I have following needs on opening file with Emacs:
emacs /path/to/file ;; default
emacs /path/to/file ;; if path doesn't exists, create it,then create the file
emacs /path/to/file:15 ;; open file and goto line 15
emacs /path/to/file:15:16 ;; open file and goto line 15 column 16
emacs /path/to.file:15:16: ;; open file and goto line 15 column 16
If you have the same functionalities implemented in your dotfile, It will be greatly appreciated if you could share it here.
Thanks!
In elisp you can use a function like this, that you can put in your init.el:
(let ((file-to-open (split-string (second command-line-args) ":")))
(progn
(find-file (first file-to-open))
(if (>= (length file-to-open) 2)
(progn (goto-char (point-min))
(forward-line
(- (string-to-int (second file-to-open)) 1))))
(if (= (length file-to-open) 3)
(forward-char
(- (string-to-int (third file-to-open)) 1)))))
What about a bash function parsing the line and col parameters?
function myemacs { if echo $1 | grep -q ":" ; then COL=$(echo $1 | cut -d: -f3); emacs $(echo $1 | cut -d: -f1) +$(echo $1 | cut -d: -f2):${COL:-0}; else emacs $1; fi }
Related
If there is a data in region:
flower
park
flower
stone
flower
stone
stone
flower
M-x some-command should give me in different buffer:
4 flower
2 stone
1 park
This data can then be sorted by frequency or item.
I suppose a common method would be to just hash the strings and then print the contents. This approach can be easily accomplished in emacs.
;; See the emacs manual for creating a hash table test
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-Hash.html
(defun case-fold-string= (a b)
(eq t (compare-strings a nil nil b nil nil t)))
(defun case-fold-string-hash (a)
(sxhash (upcase a)))
(define-hash-table-test 'case-fold
'case-fold-string= 'case-fold-string-hash)
(defun uniq (beg end)
"Print counts of strings in region."
(interactive "r")
(let ((h (make-hash-table :test 'case-fold))
(lst (split-string (buffer-substring-no-properties beg end) "\n"
'omit-nulls " "))
(output-func (if current-prefix-arg 'insert 'princ)))
(dolist (str lst)
(puthash str (1+ (gethash str h 0)) h))
(maphash (lambda (key val)
(apply output-func (list (format "%d: %s\n" val key))))
h)))
Output when selecting that text
4: flower
1: park
3: stone
I suppose there are lots of approaches you could take to this. Here's a fairly simple approach:
(defun uniq-c (beginning end)
"Like M-| uniq -c"
(interactive "r")
(let ((source (current-buffer))
(dest (generate-new-buffer "*uniq-c*"))
(case-fold-search nil))
(set-buffer dest)
(insert-buffer-substring source beginning end)
(goto-char (point-min))
(while (let* ((line (buffer-substring (line-beginning-position)
(line-end-position)))
(pattern (concat "^" (regexp-quote line) "$"))
(count (count-matches pattern (point) (point-max))))
(insert (format "%d " count))
(forward-line 1)
(flush-lines pattern)
(not (eobp))))
(pop-to-buffer dest)))
It is similar to uniq -c in bash.
Then why not use uniq -c?
With the region highlighted, M-| "sort | uniq -c", will run that command on the current region. The results will show in the minibuffer and will be listed in *Messages* buffer. Adding a prefix arg will insert the results into the current buffer.
I use blame-mercurial using the monky.el package.
In a split window, when activating blame the results come up in the other window with info about the line changed (author/changeset/date:).
I would like to have a command that searches the first line of the "result" buffer, get to where the mark ":" is and shift the border of the original buffer up till that point.
Basically, if the borders of both windows are:
| ...... | ...... |
Before executing the command:
|author 4543 11-27-2013: int x; | int x; |
After executing the command:
|author 4543 11-27-2013:| int x; |
The reason for this is I would like to keep the coloring of data types/functions...etc while seeing who last changed these source file lines.
In the blame resulted file, when the lines are proceeded with author changeset date. they loose their coloring.
So I want to use the info for each line from the blame buffer "side by side" with the original fontified file.
I also can't use a fixed window border shift value, because depending on the author(s) name length for each file the position of ":" will change accordingly.
I have modified the last version at
"Mirroring location in file in two opened buffers side by side"
such that the following code makes sense. If you run the code below and then switch on sync-window-mode for the mercury-blame buffer then isearch will have the desired effect.
(defun mercury-blame-resize ()
"Resize mercury blame window to blame string at point only."
(interactive) ;; for debugging
(window-resize (selected-window)
(- (save-excursion
(beginning-of-line)
(skip-chars-forward "^:\n"))
(window-width) -1)
'horizontal 'ignore-fixed-size))
(add-hook 'sync-window-master-hook 'mercury-blame-resize)
(add-hook 'sync-window-mode-hook '(lambda ()
(setq-local isearch-update-post-hook #'(lambda () (set-window-hscroll (selected-window) 0)))))
Version for emacs 23:
(defvar mercury-blame-resize-min 5)
(defun mercury-blame-resize ()
"Resize mercury blame window to blame string at point only."
(interactive) ;; for debugging
(save-excursion
(beginning-of-line)
(let ((n (skip-chars-forward "^:\n")))
(when (looking-at ":")
(condition-case err
(enlarge-window (- (max mercury-blame-resize-min n)
(window-width) -1)
'horizontal)
(error))))))
(add-hook 'sync-window-master-hook 'mercury-blame-resize)
(add-hook 'sync-window-mode-hook '(lambda ()
(set (make-local-variable 'isearch-update-post-hook) #'(lambda () (set-window-hscroll (selected-window) 0)))))
Helper for testing (without mercury):
(loop for i from 1 upto 100 do
(loop for j from 0 upto (random 20) do
(insert (+ 32 (random 20))))
(insert ":\n"))
EDIT: In version for emacs 23: Only re-size mercurity blame buffer when there is a ":" on the current line.
I've tried to write a simple test (kill-buffer-test.el):
:; exec emacs -Q --script "$0" -- "$#"
(setq debug-on-error t)
(setq n 0)
(dolist (idx (buffer-list))
(message "%d '%s' %s" n idx (buffer-list))
(setq n (+ 1 n))
(message "result: %s cb='%s'\n" (kill-buffer idx) (current-buffer)))
And run it:
$ ./kill-buffer-test.el
0 '*scratch*' (*scratch* *Minibuf-0* *Messages* *code-conversion-work* *load*)
result: t cb='*Messages*'
1 ' *Minibuf-0*' ( *Minibuf-0* *Messages* *code-conversion-work* *load*)
result: nil cb='*Messages*'
2 '*Messages*' ( *Minibuf-0* *Messages* *code-conversion-work* *load*)
result: t cb='*scratch*'
3 ' *code-conversion-work*' ( *Minibuf-0* *code-conversion-work* *load* *scratch* *Messages*)
result: t cb='*scratch*'
4 ' *load*' ( *Minibuf-0* *load* *scratch* *Messages*)
result: t cb='*scratch*'
Selecting deleted buffer
$ echo $?
255
Notice that *Minibuf-0* buffer wasn't killed (why?), *scratch* was resurrected, and emacs exited with a strange error message.
So, should I worry that (current-buffer) may fail? And if I should, how to test that? (current-buffer) will raise an error or will just return nil?
M-x version
GNU Emacs 24.3.50.1 (i686-pc-linux-gnu, X toolkit) of 2013-02-08 on linux.9bf016
No need to worry: (current-buffer) can't fail (Emacs would crash and burn if it ever did).
*scratch* as well as a few other internal buffers get re-generated as/when needed.
The original string is like this:
# chrom,name,strand,txStart
And the result should looks like this:
# $1: chrom
# $2: name
# $3: strand
# $4: txStart
Does anyone have idea of a quick way to do that?
Lots of ways.
You could use a search and replace making use of the \# counter in the replacement. That's zero-based, so you'd either need to add a dummy replacement at the front to use up the zero, or else use the elisp replacement expression \,(1+ \#) instead.
You could use a keyboard macro, and insert a counter with C-xC-kTAB or <f3>. You can seed that counter by supplying a prefix argument when you start recording.
On Emacs 24 you can number the lines of a marked region using a custom format string with C-uC-xrN, so your format string could be # $%1d:
Evaluate following code and execute foo function on input line.
(require 'cl)
(defun foo ()
(interactive)
(let* ((str (buffer-substring-no-properties
(line-beginning-position) (line-end-position)))
(words-str (and (string-match "# \\(.+\\)$" str)
(match-string 1 str)))
(buf (get-buffer-create "*tmp*")))
(unless words-str
(error "Line should be '# word1,word2,...'"))
(with-current-buffer buf
(erase-buffer)
(loop with index = 1
for word in (split-string words-str ",")
do
(progn
(insert (format "# $%d: %s\n" index word))
(incf index)))
(pop-to-buffer buf))))
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")))