Skip to content

Commit 4c346ad

Browse files
committed
release 1.3.0
2 parents 1d6f46a + 35ebfdf commit 4c346ad

File tree

2 files changed

+168
-54
lines changed

2 files changed

+168
-54
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ What's new in 1.0 ?
2020
* `k` : delete current gist
2121
* `+` : add a file to the current gist
2222
* `-` : remove a file from the current gist
23+
* `y` : print current gist url
24+
* `b` : browse current gist
25+
* `*` : star gist
26+
* `^` : unstar gist
27+
* `f` : fork gist
2328
* in-place edition. While viewing a gist file buffer, you can:
2429
* `C-x C-s` : save a new version of the gist
2530
* `C-x C-w` : rename some file

gist.el

+163-54
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
;; Michael Ivey
88
;; Phil Hagelberg
99
;; Dan McKinley
10-
;; Version: 1.2.2
11-
;; Package-Requires: ((eieio "1.4") (gh "0.9.2") (tabulated-list "0"))
10+
;; Version: 1.3.0
11+
;; Package-Requires: ((emacs "24.1") (gh "0.9.2"))
1212
;; Keywords: tools
1313
;; Homepage: https://github.com/defunkt/gist.el
1414

@@ -42,6 +42,7 @@
4242
(require 'eieio-base)
4343
(require 'timezone)
4444

45+
(require 'gh-api)
4546
(require 'gh-gist)
4647
(require 'gh-profile)
4748

@@ -138,13 +139,25 @@ appropriate modes from fetched gist files (based on filenames)."
138139
:value-type (string :tag "Extension")))
139140

140141
(defvar gist-list-db nil)
142+
(unless (hash-table-p gist-list-db)
143+
(setq gist-list-db (make-hash-table :test 'equal)))
144+
145+
(defvar gist-list-db-by-user nil)
146+
(unless (hash-table-p gist-list-db-by-user)
147+
(setq gist-list-db-by-user (make-hash-table :test 'equal)))
141148

142149
(defvar gist-id nil)
143150
(make-variable-buffer-local 'gist-id)
144151

145152
(defvar gist-filename nil)
146153
(make-variable-buffer-local 'gist-filename)
147154

155+
(defvar gist-user-history nil "History list for gist-list-user.")
156+
157+
(defvar gist-list-buffer-user nil "Username for this gist buffer.")
158+
(make-variable-buffer-local 'gist-list-buffer-user)
159+
(put 'gist-list-buffer-user 'permanent-local t)
160+
148161
(defun gist-get-api (&optional sync)
149162
(let ((gh-profile-current-profile
150163
(or gh-profile-current-profile (gh-profile-completing-read))))
@@ -202,7 +215,7 @@ With a prefix argument, makes a private paste."
202215

203216
(defun gist-created-callback (gist)
204217
(let ((location (oref gist :html-url)))
205-
(gist-list-reload t)
218+
(gist-list-reload 'current-user t)
206219
(message gist-created-fmt location)
207220
(when gist-view-gist
208221
(browse-url location))
@@ -256,24 +269,47 @@ Copies the URL into the kill ring."
256269
(mark-inactive (gist-buffer-private))))
257270

258271
;;;###autoload
259-
(defun gist-list (&optional force-reload background)
260-
"Displays a list of all of the current user's gists in a new buffer."
261-
(interactive "P")
272+
(defun gist-list-user (username &optional force-reload background)
273+
"Displays a list of a user's gists in a new buffer. When called from
274+
a program, pass 'current-user as the username to view the user's own
275+
gists, or nil for the username and a non-nil value for force-reload to
276+
reload the gists for the current buffer."
277+
(interactive
278+
(let ((username (read-from-minibuffer "GitHub user: " nil nil nil
279+
'gist-user-history))
280+
(force-reload (equal current-prefix-arg '(4))))
281+
(list username force-reload)))
262282
;; if buffer exists, it contains the current gh profile
263283
(let* ((gh-profile-current-profile (or gh-profile-current-profile
264284
(gh-profile-completing-read)))
265-
(bufname (format "*%s:gists*" gh-profile-current-profile))
266-
(api (gist-get-api nil)))
285+
(bufname (if (null username)
286+
(if (not (equal major-mode 'gist-list-mode))
287+
(error "Current buffer isn't a gist-list-mode buffer")
288+
(buffer-name))
289+
(format "*%s:%sgists*"
290+
gh-profile-current-profile
291+
(if (or (equal "" username)
292+
(eq 'current-user username))
293+
""
294+
(format "%s's-" username)))))
295+
(api (gist-get-api nil))
296+
(username (or (and (null username) gist-list-buffer-user)
297+
(and (not (or (null username)
298+
(equal "" username)
299+
(eq 'current-user username)))
300+
username)
301+
(gh-api-get-username api))))
267302
(when force-reload
268303
(pcache-clear (oref api :cache))
269-
(or background (message "Retrieving list of your gists...")))
304+
(or background (message "Retrieving list of gists...")))
270305
(unless (and background (not (get-buffer bufname)))
271-
(let ((resp (gh-gist-list api)))
306+
(let ((resp (gh-gist-list api username)))
272307
(gh-url-add-response-callback
273308
resp
274309
(lexical-let ((buffer bufname))
275310
(lambda (gists)
276311
(with-current-buffer (get-buffer-create buffer)
312+
(setq gist-list-buffer-user username)
277313
(gist-lists-retrieved-callback gists background)))))
278314
(gh-url-add-response-callback
279315
resp
@@ -283,9 +319,15 @@ Copies the URL into the kill ring."
283319
(with-current-buffer buffer
284320
(setq gh-profile-current-profile profile)))))))))
285321

286-
(defun gist-list-reload (&optional background)
322+
;;;###autoload
323+
(defun gist-list (&optional force-reload background)
324+
"Displays a list of all of the current user's gists in a new buffer."
325+
(interactive "P")
326+
(gist-list-user 'current-user force-reload background))
327+
328+
(defun gist-list-reload (&optional username background)
287329
(interactive)
288-
(gist-list t background))
330+
(gist-list-user username t background))
289331

290332
(defun gist-tabulated-entry (gist)
291333
(let* ((data (gist-parse-gist gist))
@@ -295,8 +337,13 @@ Copies the URL into the kill ring."
295337
(defun gist-lists-retrieved-callback (gists &optional background)
296338
"Called when the list of gists has been retrieved. Displays
297339
the list."
298-
(setq gist-list-db gists)
299-
(gist-list-render background))
340+
(dolist (g (gethash gist-list-buffer-user gist-list-db-by-user))
341+
(remhash (oref g :id) gist-list-db))
342+
(dolist (g gists)
343+
(puthash (oref g :id) g gist-list-db))
344+
(puthash gist-list-buffer-user gists gist-list-db-by-user)
345+
(gist-list-render (gethash gist-list-buffer-user gist-list-db-by-user)
346+
background))
300347

301348
(defun gist--get-time (gist)
302349
(let* ((date (timezone-parse-date (oref gist :date)))
@@ -337,15 +384,18 @@ for the gist."
337384
(interactive "sGist ID: ")
338385
(let ((gist nil)
339386
(multi nil)
340-
(prefix (format "*gist %s*" id))
387+
(prefix (format "*gist-%s*" id))
341388
(result nil)
342389
(profile (gh-profile-current-profile)))
343390
(setq gist (gist-list-db-get-gist id))
344391
(let ((api (gist-get-api t)))
345392
(cond ((null gist)
346393
;; fetch it
347394
(setq gist (oref (gh-gist-get api id) :data))
348-
(add-to-list 'gist-list-db gist))
395+
(puthash (oref gist :id) gist gist-list-db)
396+
(let* ((user (oref gist :user))
397+
(gists (push gist (gethash user gist-list-db-by-user))))
398+
(puthash user gists gist-list-db-by-user)))
349399
((not (gh-gist-gist-has-files gist))
350400
(gh-gist-get api gist))))
351401
(let ((files (oref gist :files)))
@@ -393,16 +443,25 @@ for the gist."
393443
(gist-fetch-current)
394444
(select-window win)))
395445

446+
(defun gist--check-perms-and-get-api (gist errormsg apiflg)
447+
(let* ((api (gist-get-api apiflg))
448+
(username (gh-api-get-username api))
449+
(gs (gethash username gist-list-db-by-user)))
450+
(if (not (memq gist gs))
451+
(user-error errormsg)
452+
api)))
453+
396454
(defun gist-edit-current-description ()
397455
(interactive)
398456
(let* ((id (tabulated-list-get-id))
399457
(gist (gist-list-db-get-gist id))
400-
(old-descr (oref gist :description))
401-
(new-descr (read-from-minibuffer "Description: " old-descr)))
402-
(let* ((g (clone gist
458+
(api (gist--check-perms-and-get-api
459+
gist "Can't edit a gist that doesn't belong to you" t)))
460+
(let* ((old-descr (oref gist :description))
461+
(new-descr (read-from-minibuffer "Description: " old-descr))
462+
(g (clone gist
403463
:files nil
404464
:description new-descr))
405-
(api (gist-get-api t))
406465
(resp (gh-gist-edit api g)))
407466
(gh-url-add-response-callback resp
408467
(lambda (gist)
@@ -413,18 +472,20 @@ for the gist."
413472
(let* ((buffer (get-buffer buffer))
414473
(id (tabulated-list-get-id))
415474
(gist (gist-list-db-get-gist id))
416-
(fname (file-name-nondirectory (or (buffer-file-name buffer) (buffer-name buffer)))))
417-
(let* ((g (clone gist :files
418-
(list
419-
(gh-gist-gist-file "file"
420-
:filename fname
421-
:content (with-current-buffer buffer
422-
(buffer-string ))))))
423-
(api (gist-get-api t))
424-
(resp (gh-gist-edit api g)))
425-
(gh-url-add-response-callback resp
426-
(lambda (gist)
427-
(gist-list-reload))))))
475+
(api (gist--check-perms-and-get-api
476+
gist "Can't modify a gist that doesn't belong to you" t))
477+
(fname (file-name-nondirectory (or (buffer-file-name buffer)
478+
(buffer-name buffer))))
479+
(g (clone gist :files
480+
(list
481+
(gh-gist-gist-file "file"
482+
:filename fname
483+
:content (with-current-buffer buffer
484+
(buffer-string))))))
485+
(resp (gh-gist-edit api g)))
486+
(gh-url-add-response-callback resp
487+
(lambda (gist)
488+
(gist-list-reload)))))
428489

429490
(defun gist-remove-file (fname)
430491
(interactive (list
@@ -435,24 +496,27 @@ for the gist."
435496
(mapcar #'(lambda (f) (oref f :filename))
436497
(oref gist :files))))))
437498
(let* ((id (tabulated-list-get-id))
438-
(gist (gist-list-db-get-gist id)))
439-
(let* ((g (clone gist :files
440-
(list
441-
(gh-gist-gist-file "file"
442-
:filename fname
443-
:content nil))))
444-
(api (gist-get-api t))
445-
(resp (gh-gist-edit api g)))
446-
(gh-url-add-response-callback resp
447-
(lambda (gist)
448-
(gist-list-reload))))))
499+
(gist (gist-list-db-get-gist id))
500+
(api (gist--check-perms-and-get-api
501+
gist "Can't modify a gist that doesn't belong to you" t))
502+
(g (clone gist :files
503+
(list
504+
(gh-gist-gist-file "file"
505+
:filename fname
506+
:content nil))))
507+
(resp (gh-gist-edit api g)))
508+
(gh-url-add-response-callback resp
509+
(lambda (gist)
510+
(gist-list-reload)))))
449511

450512
(defun gist-kill-current ()
451513
(interactive)
452-
(let ((id (tabulated-list-get-id)))
514+
(let* ((id (tabulated-list-get-id))
515+
(gist (gist-list-db-get-gist id))
516+
(api (gist--check-perms-and-get-api
517+
gist "Can't delete a gist that doesn't belong to you" t)))
453518
(when (yes-or-no-p (format "Really delete gist %s ? " id) )
454-
(let* ((api (gist-get-api t))
455-
(resp (gh-gist-delete api id)))
519+
(let* ((resp (gh-gist-delete api id)))
456520
(gist-list-reload)))))
457521

458522
(defun gist-current-url ()
@@ -472,6 +536,49 @@ put it into `kill-ring'."
472536
(interactive)
473537
(browse-url (gist-current-url)))
474538

539+
(defun gist--do-star (id how msg)
540+
(let* ((api (gist-get-api t))
541+
(resp (gh-gist-set-star api id how)))
542+
(gh-url-add-response-callback resp
543+
(lambda (gist)
544+
(message msg id)))))
545+
546+
;;;###autoload
547+
(defun gist-star ()
548+
(interactive)
549+
(let ((id (tabulated-list-get-id)))
550+
(gist--do-star id t "Starred gist %s")))
551+
552+
;;;###autoload
553+
(defun gist-unstar ()
554+
(interactive)
555+
(let ((id (tabulated-list-get-id)))
556+
(gist--do-star id nil "Unstarred gist %s")))
557+
558+
;;;###autoload
559+
(defun gist-list-starred (&optional background)
560+
"List your starred gists."
561+
(interactive)
562+
(let* ((api (gist-get-api t))
563+
(resp (gh-gist-list-starred api)))
564+
(gh-url-add-response-callback
565+
resp
566+
(lexical-let ((buffer "*starred-gists*"))
567+
(lambda (gists)
568+
(with-current-buffer (get-buffer-create buffer)
569+
(gist-list-render gists background)))))))
570+
571+
;;;###autoload
572+
(defun gist-fork ()
573+
"Fork a gist."
574+
(interactive)
575+
(let* ((id (tabulated-list-get-id))
576+
(api (gist-get-api))
577+
(resp (gh-gist-fork api id)))
578+
(gh-url-add-response-callback resp
579+
(lambda (gist)
580+
(message "Forked gist %s" id)))))
581+
475582
(defvar gist-list-menu-mode-map
476583
(let ((map (make-sparse-keymap)))
477584
(set-keymap-parent map tabulated-list-mode-map)
@@ -484,6 +591,9 @@ put it into `kill-ring'."
484591
(define-key map "-" 'gist-remove-file)
485592
(define-key map "y" 'gist-print-current-url)
486593
(define-key map "b" 'gist-browse-current-url)
594+
(define-key map "*" 'gist-star)
595+
(define-key map "^" 'gist-unstar)
596+
(define-key map "f" 'gist-fork)
487597
map))
488598

489599
(define-derived-mode gist-list-mode tabulated-list-mode "Gist Menu"
@@ -499,20 +609,20 @@ put it into `kill-ring'."
499609
(tabulated-list-init-header)
500610
(use-local-map gist-list-menu-mode-map))
501611

502-
(defun gist-list-render (&optional background)
612+
(defun gist-list-render (gists &optional background)
503613
(gist-list-mode)
504-
(setq tabulated-list-entries
505-
(mapcar 'gist-tabulated-entry gist-list-db))
614+
(setq tabulated-list-entries (mapcar 'gist-tabulated-entry gists))
506615
(tabulated-list-print)
507616
(gist-list-tag-multi-files)
508617
(unless background
509618
(set-window-buffer nil (current-buffer))))
510619

511620
(defun gist-list-tag-multi-files ()
512621
(let ((ids nil))
513-
(dolist (gist gist-list-db)
514-
(when (< 1 (length (oref gist :files)))
515-
(push (oref gist :id) ids)))
622+
(maphash (lambda (k v)
623+
(when (< 1 (length (oref v :files)))
624+
(push (oref v :id) ids)))
625+
gist-list-db)
516626
(save-excursion
517627
(goto-char (point-min))
518628
(while (not (eobp))
@@ -521,8 +631,7 @@ put it into `kill-ring'."
521631
(forward-line 1))))))
522632

523633
(defun gist-list-db-get-gist (id)
524-
(loop for gist in gist-list-db if (string= (oref gist :id) id)
525-
return gist))
634+
(gethash id gist-list-db))
526635

527636
;;; Gist minor mode
528637

0 commit comments

Comments
 (0)