How to read contents of the file programmatically in Emacs? - emacs

I want to read config.json file inside .emacs, how can I do this?
(require 'json)
(setq config (json-read-from-string (read-file "config.json")))

You can simplify your code to:
(defun my-file-contents (filename)
"Return the contents of FILENAME."
(with-temp-buffer
(insert-file-contents filename)
(buffer-string)))
edit: Although in this particular instance, I see that json-read-file is already defined, which cuts out the middle man.
Emacs 24.5 defines it like so:
(defun json-read-file (file)
"Read the first JSON object contained in FILE and return it."
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(json-read)))

For JSON just use json-read-file. For general files f library provides f-read-bytes and f-read-text:
(f-read-text "file.txt" 'utf-8)

I ended up with this code:
(defun read-file (filename)
(save-excursion
(let ((new (get-buffer-create filename)) (current (current-buffer)))
(switch-to-buffer new)
(insert-file-contents filename)
(mark-whole-buffer)
(let ((contents (buffer-substring (mark) (point))))
(kill-buffer new)
(switch-to-buffer current)
contents))))

For those you dislike writing quite so much code you can use f-read from the f library (not part of the standard library). This comes from this question: elisp: read file into list of lists

Related

Idiomatic way serialization in emacs lisp

Currently I am working on a elisp major mode that makes uses of hashtables across sessions. So every time the major mode is initialized, the tables are loaded into memory. During and at the end of the session they are written to a file. My current implementation writes the data in the following way:
(with-temp-buffer
(prin1 hash-table (current-buffer))
(write-file ("path/to/file.el"))))
Loading the data at the beginning of the session is done via read and is something like this:
(setq name-of-table (car
(read-from-string
(with-temp-buffer
(insert-file-contents path-of-file)
(buffer-substring-no-properties
(point-min)
(point-max))))))))
It works but I have the feeling that this is not the most beautiful way to do it. My aim is: I want this major mode to turn into a nice clean package that stores it's own data in the folder where the other data of the package is stored.
This is how I implement
Write to file:
(defun my-write (file data)
(with-temp-file file
(prin1 data (current-buffer))))
Read from file:
(defun my-read (file symbol)
(when (boundp symbol)
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(set symbol (read (current-buffer))))))
Call to write:
(my-write "~/test.txt" emacs-version)
Call to read
(my-read "~/test.txt" 'my-emacs-version)
I came up with the following solution, inspired by the first answer here:
(with-temp-buffer
(insert "(setq hash-table ")
(prin1 hash-table (current-buffer)
(insert ")")
(write-file (locate-library "my-data-lib"))
And during the init of the major mode, I just do:
(load "my-data-lib")
No need for and read-operation and the plus is that I also don't need to give any filepath, just the fact that there is such a file somewhere on the load-path is enough. Emacs will find it.
elisp rocks. :)
The package desktop can do it for you:
(require 'desktop)
(unless (memq 'hash-table desktop-globals-to-save)
(nconc desktop-globals-to-save (list 'hash-table)))`

Emacs: load-file .emacs when saved

I'm new to emacs and lisp.
I wanted to auto-load the dot file when it was saved. Meaning, when I save my .emacs file, it would automatically call load-file on it (thus letting me know right away if I messed up).
But I can't seen to be able to find a comprehensive tutorial on hooks in emacs.
This is what I've come up with:
(defun load-init-after-save ()
"After saving this file, load it"
(if (eq bname this) ('load-file this) (nil))
)
(add-hook 'after-save-hook 'load-init-after-save)
Of course, this is incorrect: bname and this are just placeholders. And I don't want this function to run on all saves, just when the .emacs file is saved.
Does anyone know how to do this? Is there a better, easier way?
The following code loads your .emacs or ~/.emacs.d/init.el file after save:
(defun my-load-user-init-file-after-save ()
(when (string= (file-truename user-init-file)
(file-truename (buffer-file-name)))
(let ((debug-on-error t))
(load (buffer-file-name)))))
(add-hook 'after-save-hook #'my-load-user-init-file-after-save)
Since your intended use is error-checking, the code also enables the debugger while loading the init file, so that you get a nice backtrace in case of errors.
For error checking of your init file you may also find Flycheck useful. It checks your init file on the fly with the byte compiler, highlights any errors and warnings in the buffer, and—optionally—gives you a list of all errors and warnings.
Disclaimer: I'm the maintainer of this library.
Way 1
One way of doing is to install auto-compile-mode from MELPA, and enable it:
(defun my-emacs-lisp-hook ()
(auto-compile-mode 1))
(add-hook 'emacs-lisp-mode-hook 'my-emacs-lisp-hook)
Now each time you save an Elisp file that's byte-compiled, it will be
re-compiled. Compilation will usually catch some bad errors.
To compile any Elisp file, select it in dired (C-x d)
and press B (dired-do-byte-compile).
Way 2
Use this custom code I wrote.
(defun test-emacs ()
(interactive)
(require 'async)
(async-start
(lambda () (shell-command-to-string "emacs --batch --eval \"(condition-case e (progn (load \\\"~/.emacs\\\") (message \\\"-OK-\\\")) (error (message \\\"ERROR!\\\") (signal (car e) (cdr e))))\""))
`(lambda (output)
(if (string-match "-OK-" output)
(when ,(called-interactively-p 'any)
(message "All is well"))
(switch-to-buffer-other-window "*startup error*")
(delete-region (point-min) (point-max))
(insert output)
(search-backward "ERROR!")))))
(defun auto-test-emacs ()
(when (eq major-mode 'emacs-lisp-mode))
(test-emacs))
(add-hook 'after-save-hook 'auto-test-emacs)
This will start a new Emacs instance in the background each time you
save a file. If something goes wrong, it will complain.
The second approach uses async.
If you really want to do this just for .emacs user this:
(defun auto-test-emacs ()
(when (and (eq major-mode 'emacs-lisp-mode)
(equal (file-truename user-init-file)
(expand-file-name
buffer-file-truename)))
(test-emacs)))

Easy way to go to the definition of a function (Emacs, Ocaml)

I am coding Ocaml under Emacs...
I would like to know if there is a shortcut to jump to the definition of a function (where the cursor is). At the moment, to do so I have to search the name of the function in the whole file, or look for let the_name_of_the_function and let rec the_name_of_the_function and and the_name_of_the_function which is obviously tedious...
By the way, I have alreay the file .annot.
Could anyone help? Thank you!
My ctags(1) (from the exuberant-ctags package) supports the OCaml language and Emacs supports ctags when it is executed as etags.
So try: cd /path/to/Ocaml/sources/ && etags -R . to build an index, and then within emacs, M-.ret to search for the tag under the cursor.
The problem could be solved with merlin (https://github.com/the-lambda-church/merlin). Merlin can be installed easily with opam:
opam install merlin
Follow the instructions provided by opam to configure ~/.emacs file. To finish the configuration you will have to provide a .merlin file that tells merlin where the source files and build files are located and which packages are used in the project. A brief overview of the .merlin file is given in https://github.com/the-lambda-church/merlin/wiki/emacs-from-scratch#configuring-your-project
Now, to jump to the function definition in Emacs:
C-c C-l
To move back to the function call:
C-c &
While you are waiting for a better solution (of which there are some, see for example OCamlSpotter) you can use the poor-man commands listed below. Assumes tuareg-mode.
(defun camldev-identifier-at-point ()
(interactive)
(save-excursion
(goto-char (1+ (point)))
(let* ((beg (re-search-backward "[^A-Za-z0-9_'][A-Za-z0-9_'`]"))
(beg (1+ beg)))
(goto-char (1+ beg))
(let* ((end (re-search-forward "[^A-Za-z0-9_']"))
(end (1- end)))
(buffer-substring beg end)))))
(defun camldev-goto-def ()
"Search for definition of word around point."
(interactive)
(let (goal (word (camldev-identifier-at-point)))
(save-excursion
(re-search-backward (concat "\\(let \\([^=]*[^A-Za-z0-9_']\\|\\)"
word "\\([^A-Za-z0-9_'][^=]*\\|\\)=\\|"
"fun \\([^-]*[^A-Za-z0-9_']\\|\\)"
word "\\([^A-Za-z0-9_'][^-]*\\|\\)->\\|"
"and \\([^=]*[^A-Za-z0-9_']\\|\\)"
word "\\([^A-Za-z0-9_'][^=]*\\|\\)=\\)"
))
(re-search-forward (concat "[^A-Za-z0-9_']" word "[^A-Za-z0-9_']"))
(setq goal (1+ (match-beginning 0))))
(push-mark)
(goto-char goal)
))
(defun camldev-goto-spec ()
"Search for specification in mli/ml file of word around point in ml/mli file."
(interactive)
(let* (goal
(word (camldev-identifier-at-point))
(search-expr (concat "\\(val [^:\n]*"
word "[^:]*:\\|"
"let [^=\n]*"
word "[^=]*=\\|"
"type [^=\n]*"
word "[^=]*=\\)"
)))
(tuareg-find-alternate-file)
(save-excursion
(goto-char (point-min))
(re-search-forward search-expr)
(setq goal (match-beginning 0)))
(push-mark)
(goto-char goal)
))
(define-key tuareg-mode-map (kbd "C-c C-d") 'camldev-goto-def)
(define-key tuareg-mode-map (kbd "C-c C-S-d") 'camldev-goto-spec)
You can try otags located here:
http://askra.de/software/otags/
From the project page:
Otags generates TAGS files suitable for emacs and vi/vim from OCaml
sources. Otags employs camlp4 for parsing.
To use it, try something like:
otags -r src/
where src is the subdirectory containing your OCaml source files.
It should create a TAGS file.
Then you should be able to do M-. in Emacs.
You can install otags with opam.

How to find the files in TAGS file in emacs

I have generated the TAGS file using ctags for the *.h and *.cpp file in a directory.
How to find the files in TAGS file.
Assuming i have generated the TAGS file for the files one.h two.h three.h. What is the command to find the file one.h, two.h, three.h not the tags in those files.
Assuming that you simply want to know how to use the TAGS file...
Load the TAGS file with:
M-x visit-tags-table RET TAGS file or parent directory RET
Then you can use it with:
M-. (i.e. find-tag)
M-x tags-search RET pattern RET
(with M-, to move to each successive match)
M-x tags-apropos RET pattern RET
M-x tags-query-replace RET pattern RET replacement RET
Those are the defaults. Naturally there are enhancements available:
http://www.emacswiki.org/emacs/EmacsTags
Personally I use etags-select (which you can obtain via ELPA), and I have M-. bound to etags-select-find-tag.
I wrote this a couple of years ago, I haven't gotten around to releasing it yet, though... Enjoy!
The function tags-extra-find-file will let you visit a file in the current tags table, complete with file-name completion. This is perfect if you have many source files spread out over a large number of directories. (Honestly, I use this at least one hundred times every day...)
(defun tags-extra-get-all-tags-files ()
"Return all, fully qualified, file names."
(save-excursion
(let ((first-time t))
(while (visit-tags-table-buffer (not first-time))
(setq first-time nil)
(setq res
(append res (mapcar 'expand-file-name (tags-table-files)))))))
res))
(defun tags-extra-find-file (name)
"Edit file named NAME that is part of the current tags table.
The file name should not include parts of the path."
(interactive
(list
(completing-read "Name of file: "
;; Make an a-list of all files without path.
(mapcar
(lambda (file)
(cons (file-name-nondirectory file) nil))
(tags-extra-get-all-tags-files)))))
(let ((files (tags-extra-get-all-tags-files))
(done nil)
(name-re (concat "^" (regexp-quote name) "$")))
(while (and (not done)
files)
(let ((case-fold-search t))
(if (string-match name-re (file-name-nondirectory (car files)))
(setq done t)
(setq files (cdr files)))))
(if files
(find-file (car files))
(error "File not found in the tags table."))))
This correction works in emacs 26.3. With an old etags, M-. would accept a file name, such as Setup.cpp, and visit the file wherever etags found it. Very handy with lots of files in many directories. No need to remember what directory the file was in to visit it. I'm surprised that's not an out-of-the-box feature!
(defun tags-extra-get-all-tags-files ()
"Return all, fully qualified, file names."
(setq res nil)
(save-excursion
(let ((first-time t))
(while (visit-tags-table-buffer (not first-time))
(setq first-time nil)
(setq res
(append res (mapcar 'expand-file-name (tags-table-files)))))))
res)
Something like this? It might not be entirely robust.
(defun visit-tags-table-and-files (file)
"Run `visit-tags-table FILE', then visit all the referenced files."
(interactive "fTags file: ")
(visit-tags-table file)
(save-excursion
(set-buffer (get-file-buffer tags-file-name))
(mapc #'find-file (tags-table-files)) ) )
Thanks #Lindydancer's answer and emacswiki ido. The emacswiki version only support one tag file. Combining them which allows me jumping to any file in all TAG files. Petty close to the sublime text's goto anything.
Here is the code.
;;; using ido find file in tag files
(defun tags-extra-get-all-tags-files ()
"Return all, fully qualified, file names."
(save-excursion
(let ((first-time t)
(res nil))
(while (visit-tags-table-buffer (not first-time))
(setq first-time nil)
(setq res
(append res (mapcar 'expand-file-name (tags-table-files)))))
res)))
(defun ido-find-file-in-tag-files ()
(interactive)
(find-file
(expand-file-name
(ido-completing-read
"Files: " (tags-extra-get-all-tags-files) nil t))))

File path to clipboard in Emacs

What is the most simple way to send current full file name with file path to clipboard?
What I am using now is messages buffer: I copy file name that appears there after saving a file. But, I suppose, there should be much more simple way.
Why no one tell the simple solution.
Just go to your dired buffer then press 0 w or C-u 0 w.
This will call dired-copy-filename-as-kill which gives you full path of a file. If you want current dir, just delete the file at the end of it or you can use the function below, then bind it to any key you like.
(defun my/dired-copy-dirname-as-kill ()
"Copy the current directory into the kill ring."
(interactive)
(kill-new default-directory))
PS: personally I go to current directory from file buffer using dired-jump
I use this:
(defun my-put-file-name-on-clipboard ()
"Put the current file name on the clipboard"
(interactive)
(let ((filename (if (equal major-mode 'dired-mode)
default-directory
(buffer-file-name))))
(when filename
(with-temp-buffer
(insert filename)
(clipboard-kill-region (point-min) (point-max)))
(message filename))))
In Emacs Prelude I use:
(defun prelude-copy-file-name-to-clipboard ()
"Copy the current buffer file name to the clipboard."
(interactive)
(let ((filename (if (equal major-mode 'dired-mode)
default-directory
(buffer-file-name))))
(when filename
(kill-new filename)
(message "Copied buffer file name '%s' to the clipboard." filename))))
If you want to write the name/path of the current buffer you can type C-u M-: and then either (buffer-file-name) - for the full path - or (buffer-name) for the buffer name.
That is:
M-: + ellisp expression evaluates an ellisp expression in the mini-buffer
C-u write the output to the current buffer
Does not exactly answer to the question but could be useful if someone use this or other function sporadically, and prefers to not initialize the function at every startup.
In the Spacemacs distribution, you can press Spacefyy to display the buffer name in the minibuffer and copy it to the kill ring.
The function spacemacs/show-and-copy-buffer-filename seems to originate from this blog post: Emacs: Show Buffer File Name.
(defun camdez/show-buffer-file-name ()
"Show the full path to the current file in the minibuffer."
(interactive)
(let ((file-name (buffer-file-name)))
(if file-name
(progn
(message file-name)
(kill-new file-name))
(error "Buffer not visiting a file"))))
There's a buffer-extension - and it has copy-buffer-file-name-as-kill function. It even asks You what to copy: name, full name or a directory name.
Edit:
I use modified version of copy-buffer-file-name-as-kill from buffer-extension.el:
(defun copy-buffer-file-name-as-kill (choice)
"Copyies the buffer {name/mode}, file {name/full path/directory} to the kill-ring."
(interactive "cCopy (b) buffer name, (m) buffer major mode, (f) full buffer-file path, (d) buffer-file directory, (n) buffer-file basename")
(let ((new-kill-string)
(name (if (eq major-mode 'dired-mode)
(dired-get-filename)
(or (buffer-file-name) ""))))
(cond ((eq choice ?f)
(setq new-kill-string name))
((eq choice ?d)
(setq new-kill-string (file-name-directory name)))
((eq choice ?n)
(setq new-kill-string (file-name-nondirectory name)))
((eq choice ?b)
(setq new-kill-string (buffer-name)))
((eq choice ?m)
(setq new-kill-string (format "%s" major-mode)))
(t (message "Quit")))
(when new-kill-string
(message "%s copied" new-kill-string)
(kill-new new-kill-string))))
If you use Doom Emacs, it can be done with SPC f y.
To paste the current file path in the buffer, the most simple way I see is to do: C-u M-! pwd (this might not work on Windows systems though).
Alternatively, you can use C-x C-b to show the file paths of all opened buffers.
This is what has worked for me on MacOS 10.15.7, GNU Emacs 27.1
(defun copy-current-buffer-file-name ()
(interactive)
(shell-command (concat "echo " (buffer-file-name) " | pbcopy")))
set keybinding to "C-x M-f":
(global-set-key (kbd "C-x M-f") 'copy-current-buffer-file-name)
FYI: For a real beginner reading this, you need to add those lines to your init.el file.
Lots of good answers here, though I think for the "most simple way", as described in the question, there's room for improvement. Here's what I came up with (with thanks to other answers for the bits and pieces):
M-: (kill-new (buffer-file-name)) RET
This does precisely what you asked for -- takes the filename of the current buffer, and puts it in the "kill ring" and, depending on your settings, also the system clipboard. (See emacswiki/CopyAndPaste for more details on that part.)
If you want to do this regularly, then setting up a function like listed in the other answers, and binding it to an available key sequence, would make it easier to do frequently. But the above works with no prior setup, which I'm interpreting to be more "simple".