Gist (gist.el / Emacs) -- Set the `description` at the time of creation - emacs

The default behavior of gist-region is to leave the description blank. To set the description, it is necessary to switch to the gist-list buffer and then use the function gist-edit-current-description to set the description.
I would like to be able to set the description at the same time that the gist is created, without switching to the gist-list buffer. A mini-buffer prompt that defaults to the buffer-name would be the preferred method of handling this. How can this be accomplished programmatically?
Here are the two main functions in gist.el that are responsible for the behavior described above:
(defun gist-region (begin end &optional private callback)
"Post the current region as a new paste at gist.github.com
Copies the URL into the kill ring.
With a prefix argument, makes a private paste."
(interactive "r\nP")
(let* ((file (or (buffer-file-name) (buffer-name)))
(name (file-name-nondirectory file))
(ext (or (cdr (assoc major-mode gist-supported-modes-alist))
(file-name-extension file)
"txt"))
(fname (concat (file-name-sans-extension name) "." ext))
(files (list
(gh-gist-gist-file "file"
:filename fname
:content (buffer-substring begin end)))))
(gist-internal-new files private nil callback)))
(defun gist-edit-current-description ()
(interactive)
(let* ((id (tabulated-list-get-id))
(gist (gist-list-db-get-gist id))
(old-descr (oref gist :description))
(new-descr (read-from-minibuffer "Description: " old-descr)))
(let* ((g (clone gist
:files nil
:description new-descr))
(api (gist-get-api t))
(resp (gh-gist-edit api g)))
(gh-url-add-response-callback resp
(lambda (gist)
(gist-list-reload))))))

Take a look at the function gist-internal-new that gist-region is calling.
(gist-internal-new FILES &optional PRIVATE DESCRIPTION CALLBACK)
The third param is the description but gist-region is setting it to nil. You can modify that last expression in gist-region to read a string from the minibuffer to specify a description
(gist-internal-new files private (read-from-minibuffer "Gist Description: ") callback)
Or better yet, don't modify the function and just write your own! That way, you don't mess with other packages that use the function.
Here is just a slightly a modified version that adds an extra parameter and uses interactive to automatically prompt the user for a description while still allowing prefix args to make private gists.
Unlike the first example when we used `read-from-minibuffer' this one will allow you to use the function in code and specify the description directly without forcing a prompt to be used unless it's called interactively.
;; note that we added the DESCRIPTION argument
(defun gist-region-with-description (begin end &optional description private callback)
"Post the current region as a new paste at gist.github.com
Copies the URL into the kill ring.
With a prefix argument, makes a private paste."
(interactive "r\nsGist Description: \nP") ;; we handle the prompt here!
(let* ((file (or (buffer-file-name) (buffer-name)))
(name (file-name-nondirectory file))
(ext (or (cdr (assoc major-mode gist-supported-modes-alist))
(file-name-extension file)
"txt"))
(fname (concat (file-name-sans-extension name) "." ext))
(files (list
(gh-gist-gist-file "file"
:filename fname
:content (buffer-substring begin end)))))
;; finally we use our new arg to specify the description in the internal call
(gist-internal-new files private description callback)))

Related

Result value of elisp code stored in a file?

Looking for a way how evaluate elisp code stored in an external file and pass its result as a function argument. Example demonstrating what I'd like to achieve follows:
;; content of my_template.el
'(this is a list)
;; content of .emacs where result of my_template.el has to be used
(define-auto-insert "\.ext$"
;; bellow is my attempt to retrieve resulting list object
;; but getting nil instead
(with-temp-buffer
(insert-file-contents ("my_template.el"))
(eval-buffer))))
Probably looking for an eval-like function which besides side-effect also returns result of the last expression.
Any idea ?
Using variable to share data is easier and more common, for example:
;; content of ~/my_template.el
(defvar my-template '(this is a list))
;; content of .emacs where result of my_template.el has to be used
(load-file "~/my_template.el")
(define-auto-insert "\.ext$"
my-template)
Update the function eval-file should do what you want:
;; content of ~/my_template.el
'(this is a list)
(defun eval-file (file)
"Execute FILE and return the result of the last expression."
(load-file file)
(with-temp-buffer
(insert-file-contents file)
(emacs-lisp-mode)
(goto-char (point-max))
(backward-sexp)
(eval (sexp-at-point))))
(eval-file "~/my_template.el")
=> (this is a list)
Update two: without evaluate the last expression twice
(defun eval-file (file)
"Execute FILE and return the result of the last expression."
(eval
(ignore-errors
(read-from-whole-string
(with-temp-buffer
(insert-file-contents file)
(buffer-string))))))
(eval-file "~/my_template.el")
=> (this is a list)
Don't read from a string. Read from a buffer.
(defun load&return (file &optional msgp)
"Load FILE. Return the value of the last sexp read."
(interactive "fFile: \np")
(let* ((sexp (with-current-buffer (find-file-noselect file)
(goto-char (point-min))
(read (current-buffer))))
(val (ignore-errors (eval sexp))))
(prog1 val (when msgp (message "Value: %S" val)))))

How to edit a Gist filename using `gist.el` with Emacs

Can anyone please steer me in the right direction regarding how to edit the filename of an existing Gist using gist.el. I've tried modifying gist-edit-current-description to handle filename modification, but my attempted variations haven't worked. Here is the gist-edit-current-description function -- I assume editing the filename would be something similar to the description:
(defun gist-edit-current-description ()
(interactive)
(let* ((id (tabulated-list-get-id))
(gist (gist-list-db-get-gist id))
(old-descr (oref gist :description))
(new-descr (read-from-minibuffer "Description: " old-descr)))
(let* ((g (clone gist
:files nil
:description new-descr))
(api (gist-get-api t))
(resp (gh-gist-edit api g)))
(gh-url-add-response-callback resp
(lambda (gist)
(gist-list-reload))))))
This may help give someone some ideas -- it is a method of setting the filename at the time of Gist creation (and it is based on a prior answer by #Jordon Biondo -- https://stackoverflow.com/a/22973794/2112489 ):
(defun gist-region-with-filename-description (begin end &optional filename description private callback)
"Post the current region as a new paste at gist.github.com
Copies the URL into the kill ring.
With a prefix argument, makes a private paste."
(interactive "r\nsGist Description: \nP") ;; we handle the prompt here!
(let* ((file (or (buffer-file-name) (buffer-name)))
(name (file-name-nondirectory file))
(ext (or (cdr (assoc major-mode gist-supported-modes-alist))
(file-name-extension file)
"txt"))
(fname (if filename filename (concat (file-name-sans-extension name) "." ext)))
(files (list
(gh-gist-gist-file "file"
:filename fname
:content (buffer-substring begin end)))))
;; finally we use our new arg to specify the description in the internal call
(gist-internal-new files private description callback)))
(defun gist-buffer-with-filename-description (&optional filename description private)
"Post the current buffer as a new paste at gist.github.com.
Copies the URL into the kill ring.
With a prefix argument, makes a private paste."
(interactive "P")
(let* (
(filename (if filename filename (read-string "Filename: " (buffer-name))))
(description (if description description (read-string "Description: " (buffer-name)))))
(gist-region-with-filename-description (point-min) (point-max) filename description private nil)))
The developer added this feature on December 29, 2014 -- the function is gist-mode-write-file, which is used when visiting the file. Issue number 55: https://github.com/defunkt/gist.el/issues/55

Asking emacs for default directory path "once"

I want to have a variable that keeps the default directory a user enters and keep using it throughout the run of emacs.
Basically, when the user executes a custom command, the prompt will ask for a default directory path to execute the command (only once) and whenever the user calls the same command emacs uses the same path onward.
How can I program that snippet of code in lisp?
I basically want this code in the igrep library to accept the input from user once and not ask again:
(defvar default-files-string-new "*.[sch]")
(defun igrep-read-files (&optional prompt-prefix)
"Read and return a file name pattern from the minibuffer.
If `current-prefix-arg' is '(16) or '(64), read multiple file name
patterns and return them in a list. Optional PROMPT-PREFIX is
prepended to the \"File(s): \" prompt."
(let* ((default-files (igrep-default-files))
(default-files-string (mapconcat 'identity default-files " "))
(insert-default-directory igrep-insert-default-directory)
(file (igrep-read-file-name
(igrep-prefix prompt-prefix
(if default-files
(format "File(s) [default: %s]: "
default-files-string)
"File(s): "))
nil (if default-files default-files-string "") nil nil
'igrep-files-history))
(files (list file)))
(if (or igrep-read-multiple-files
(and (consp current-prefix-arg)
(memq (prefix-numeric-value current-prefix-arg)
'(16 64))))
(let* ((key (igrep-default-key 'exit-minibuffer
minibuffer-local-completion-map
"\r"))
(prompt
(igrep-prefix prompt-prefix
(if igrep-verbose-prompts
(format "File(s): [Type `%s' when done] "
(key-description key))
"File(s): "))))
(while (and (setq file
(igrep-read-file-name prompt
nil "" nil nil
'igrep-files-history))
(not (equal file "")))
(setq files (cons file files)))))
(mapcar (lambda (file)
(if (file-directory-p file)
;; really should map expand-file-name over default-files:
(expand-file-name (if default-files default-files-string-new "*")
file)
file))
(nreverse files))))
You could use advices to do that:
(defvar wd-alist nil)
(mapc
(lambda (function)
(eval
`(defadvice ,function (around ,(intern (format "%s-wd" function)) activate)
(let ((wd (cdr (assoc ',function wd-alist))))
(unless wd
(setq wd (read-file-name "Default directory: "))
(push (cons ',function wd) wd-alist))
(let ((default-directory wd))
ad-do-it)))))
'(grep-find))
The variable wd-list stores the association (FUNCTION . PATH). The list mapc iterate over are the advised functions. Now, when calling find-grep, it asks for the working directory (after interactive arguments, so you first have to type the pattern and enter...) and stores it in wd-list for further use. Now your find-grep are always done in that directory.
You could have a custom variable for the sane default, and then have the user enter the path or accept the default on the first call.
(defcustom default-path "/tmp/foo" "Path")
(setq current-path nil)
(defun foo ()
(interactive)
(unless current-path
(setq current-path
(read-from-minibuffer
(format "Path [%s]" default-path) nil nil t nil default-path)))
(message "Path is: %s" current-path))
The first time you do M-x foo, it prompts for the path. A common idiom is to allow the user to specify a prefix argument when they want to change the value (after the first time.) This code will have the desired effect:
(defun foo (choose)
(interactive "P")
(when (or choose (not current-path))
(setq current-path
(read-from-minibuffer
(format "Path [%s]" default-path) nil nil t nil default-path)))
(message "Path is: %s" current-path))
Now doing M-x foo is the same as before, but C-0 M-x foo will prompt for a new value.
In your example, something like this will work.
(defun igrep-read-files (&optional prompt-prefix)
(interactive "P")
(when (or prompt-prefix (not current-path ))
(setq current-path
(read-file-name "Dir: " default-path nil t)))
(message (expand-file-name default-files-string-new current-path)))
Have a look at the code of sendmail-query-once.
Although it's not very fashionable to do this sort of thing.
Usually package writers pick a sane default and let the user
customize it as they want.

define your own tag in org-mode

There are Tags as in #+AUTHOR or #+LATEX in org-mode - are they called tags? I'd like to define my own tag which calls a function to preprocess the data and then outputs it - if the export target is LaTeX.
My solution was defining an own language, qtree, for SRC blocks.
#+BEGIN_SRC qtree
[.CP [.TP [.NP [] [.N' [.N Syntax] []]] [.VP [] [.V' [.V sucks] []]]]]
#+END_SRC
And process it accordingly. I even added a qtree-mode with paredit.
And a landscape parameter if the trees grow big. https://github.com/Tass/emacs-starter-kit/blob/master/vendor/assorted/org-babel-qtree.el
(require 'org)
(defun org-babel-execute:qtree (body params)
"Reformat a block of lisp-edited tree to one tikz-qtree likes."
(let (( tree
(concat "\\begin{tikzpicture}
\\tikzset{every tree node/.style={align=center, anchor=north}}
\\Tree "
(replace-regexp-in-string
" \\_<\\w+\\_>" (lambda (x) (concat "\\\\\\\\" (substring x 1)))
(replace-regexp-in-string
(regexp-quote "]") " ]" ; qtree needs a space
; before every closing
; bracket.
(replace-regexp-in-string
(regexp-quote "[]") "[.{}]" body)) ; empty leaf
; nodes, see
; http://tex.stackexchange.com/questions/75915
) ; For
; http://tex.stackexchange.com/questions/75217
"\n\\end{tikzpicture}"
)))
(if (assoc :landscape params)
(concat "\\begin{landscape}\n" tree "\n\\end{landscape}")
tree)))
(setq org-babel-default-header-args:qtree '((:results . "latex") (:exports . "results")))
(add-to-list 'org-src-lang-modes '("qtree" . qtree))
(define-generic-mode
'qtree-mode ;; name of the mode to create
'("%") ;; comments start with '%'
'() ;; no keywords
'(("[." . 'font-lock-operator) ;; some operators
("]" . 'font-lock-operator))
'() ;; files for which to activate this mode
'(paredit-mode) ;; other functions to call
"A mode for qtree edits" ;; doc string for this mode
)
They seem to be called keywords for in-buffer settings no more. Whatever they're called, they don't seem to be user-definable.
What you want to do is extremely related to a common way of handling whereas to export with xelatex or pdflatex as described on Worg.
The relevant part would be :
;; Originally taken from Bruno Tavernier: http://thread.gmane.org/gmane.emacs.orgmode/31150/focus=31432
(defun my-auto-tex-cmd ()
(if (string-match "YOUR_TAG: value1" (buffer-string))
(do something))
(if (string-match "YOUR_TAG: value2" (buffer-string))
(do something else))
(add-hook 'org-export-latex-after-initial-vars-hook 'my-auto-tex-cmd)

The mechanism iswtichb used to show completions

all.
I decided to hack iswitchb this morning, and found a confusing thing.
Usually,when we command iswitchb,we got someting in minibuffer like:
iswitch {buffer1,buffer2 ...}
What in braces is the completions, as we typing its number
is shrinking.
And I didn't find how iswitchb achieved this when hacking on
its code (sorry for my dullness ).
This is original iswitchb-read-buffer with doc-string ripped
off:
(defun iswitchb-read-buffer (prompt &optional default require-match
start matches-set)
(let
(
buf-sel
iswitchb-final-text
(icomplete-mode nil) ;; prevent icomplete starting up
)
(iswitchb-define-mode-map)
(setq iswitchb-exit nil)
(setq iswitchb-default
(if (bufferp default)
(buffer-name default)
default))
(setq iswitchb-text (or start ""))
(unless matches-set
(setq iswitchb-rescan t)
(iswitchb-make-buflist iswitchb-default)
(iswitchb-set-matches))
(let
((minibuffer-local-completion-map iswitchb-mode-map)
;; Record the minibuffer depth that we expect to find once
;; the minibuffer is set up and iswitchb-entryfn-p is called.
(iswitchb-minibuf-depth (1+ (minibuffer-depth)))
(iswitchb-require-match require-match))
;; prompt the user for the buffer name
(setq iswitchb-final-text (completing-read
prompt ;the prompt
'(("dummy" . 1)) ;table
nil ;predicate
nil ;require-match [handled elsewhere]
start ;initial-contents
'iswitchb-history)))
(if (and (not (eq iswitchb-exit 'usefirst))
(get-buffer iswitchb-final-text))
;; This happens for example if the buffer was chosen with the mouse.
(setq iswitchb-matches (list iswitchb-final-text)
iswitchb-virtual-buffers nil))
;; If no buffer matched, but a virtual buffer was selected, visit
;; that file now and act as though that buffer had been selected.
(if (and iswitchb-virtual-buffers
(not (iswitchb-existing-buffer-p)))
(let ((virt (car iswitchb-virtual-buffers))
(new-buf))
;; Keep the name of the buffer returned by find-file-noselect, as
;; the buffer 'virt' could be a symlink to a file of a different name.
(setq new-buf (buffer-name (find-file-noselect (cdr virt))))
(setq iswitchb-matches (list new-buf)
iswitchb-virtual-buffers nil)))
;; Handling the require-match must be done in a better way.
(if (and require-match
(not (iswitchb-existing-buffer-p)))
(error "Must specify valid buffer"))
(if (or (eq iswitchb-exit 'takeprompt)
(null iswitchb-matches))
(setq buf-sel iswitchb-final-text)
;; else take head of list
(setq buf-sel (car iswitchb-matches)))
;; Or possibly choose the default buffer
(if (equal iswitchb-final-text "")
(setq buf-sel (car iswitchb-matches)))
buf-sel))
And this is the part of iswitchb-read buffer,which I thought
is responsible for functioning completion mechanism.
(defun iswitchb-read-buffer (prompt &optional default require-match
start matches-set)
(let
(
(iswitchb-minibuf-depth (1+ (minibuffer-depth)))
)
;; prompt the user for the buffer name
(completing-read
prompt ;the prompt
'(("dummy" . 1)) ;table
nil ;predicate
nil ;require-match [handled elsewhere]
start ;initial-contents
'iswitchb-history)))
Eval
(iswitchb-read-buffer "Test: ")
resulting
Test: {buffer1,buffer2,...}
So, I think I'm right.
So,what confused me is how can sexp:
(iswitchb-minibuf-depth (1+ (minibuffer-depth)))
has effect on what echos in minibuffer. Comment this
sexp,or replace iswitchb-minibuffer-depth with another
variable, the completions will disappear.
Any advice?
This variable is used in iswitchb-entryfn-p which is called from iswitchb-minibuffer-setup
(defun iswitchb-minibuffer-setup ()
"Set up minibuffer for `iswitchb-buffer'.
Copied from `icomplete-minibuffer-setup-hook'."
(when (iswitchb-entryfn-p)
(set (make-local-variable 'iswitchb-use-mycompletion) t)
(add-hook 'pre-command-hook 'iswitchb-pre-command nil t)
(add-hook 'post-command-hook 'iswitchb-post-command nil t)
(run-hooks 'iswitchb-minibuffer-setup-hook)))
When iswitchb-minibuf-depth is null then iswitchb-entryfn-p is null and the setup is not done.
The iswitchb-minibuffer-setup is a hook which is added to the iswitchb-mode.
BTW, while this may not directly answer your question, this part of iswitchb's behavior is also provided by icomplete-mode (for the normal completion code).