Compare commits
No commits in common. "fad5a5f91dd55277246675f43ce279a14cf482f4" and "cb49eaf0afd1e2e004a6865bf4d7dd93a67187f5" have entirely different histories.
fad5a5f91d
...
cb49eaf0af
|
@ -1,6 +1,6 @@
|
||||||
(define-package "all-the-icons" "20240623.1800" "A library for inserting Developer icons"
|
(define-package "all-the-icons" "20240108.559" "A library for inserting Developer icons"
|
||||||
'((emacs "24.3"))
|
'((emacs "24.3"))
|
||||||
:commit "39ef44f810c34e8900978788467cc675870bcd19" :authors
|
:commit "ee414384938ccf2ce93c77d717b85dc5538a257d" :authors
|
||||||
'(("Dominic Charlesworth" . "dgc336@gmail.com"))
|
'(("Dominic Charlesworth" . "dgc336@gmail.com"))
|
||||||
:maintainers
|
:maintainers
|
||||||
'(("Dominic Charlesworth" . "dgc336@gmail.com"))
|
'(("Dominic Charlesworth" . "dgc336@gmail.com"))
|
|
@ -168,12 +168,6 @@
|
||||||
("dll" all-the-icons-faicon "cogs" :face all-the-icons-silver)
|
("dll" all-the-icons-faicon "cogs" :face all-the-icons-silver)
|
||||||
("ds_store" all-the-icons-faicon "cogs" :face all-the-icons-silver)
|
("ds_store" all-the-icons-faicon "cogs" :face all-the-icons-silver)
|
||||||
;; Source Codes
|
;; Source Codes
|
||||||
("ada" all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-blue)
|
|
||||||
("adb" all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-blue)
|
|
||||||
("adc" all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-blue)
|
|
||||||
("ads" all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-blue)
|
|
||||||
("gpr" all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-green)
|
|
||||||
("cgpr" all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-green)
|
|
||||||
("scpt" all-the-icons-fileicon "apple" :face all-the-icons-pink)
|
("scpt" all-the-icons-fileicon "apple" :face all-the-icons-pink)
|
||||||
("aup" all-the-icons-fileicon "audacity" :face all-the-icons-yellow)
|
("aup" all-the-icons-fileicon "audacity" :face all-the-icons-yellow)
|
||||||
("elm" all-the-icons-fileicon "elm" :face all-the-icons-blue)
|
("elm" all-the-icons-fileicon "elm" :face all-the-icons-blue)
|
||||||
|
@ -190,6 +184,7 @@
|
||||||
("eclass" all-the-icons-fileicon "gentoo" :face all-the-icons-blue)
|
("eclass" all-the-icons-fileicon "gentoo" :face all-the-icons-blue)
|
||||||
("go" all-the-icons-fileicon "go" :height 1.0 :face all-the-icons-blue)
|
("go" all-the-icons-fileicon "go" :height 1.0 :face all-the-icons-blue)
|
||||||
("jl" all-the-icons-fileicon "julia" :face all-the-icons-purple :v-adjust 0.0)
|
("jl" all-the-icons-fileicon "julia" :face all-the-icons-purple :v-adjust 0.0)
|
||||||
|
("magik" all-the-icons-faicon "magic" :face all-the-icons-blue)
|
||||||
("matlab" all-the-icons-fileicon "matlab" :face all-the-icons-orange)
|
("matlab" all-the-icons-fileicon "matlab" :face all-the-icons-orange)
|
||||||
("nix" all-the-icons-fileicon "nix" :face all-the-icons-blue)
|
("nix" all-the-icons-fileicon "nix" :face all-the-icons-blue)
|
||||||
("pl" all-the-icons-alltheicon "perl" :face all-the-icons-lorange)
|
("pl" all-the-icons-alltheicon "perl" :face all-the-icons-lorange)
|
||||||
|
@ -688,8 +683,6 @@ for performance sake.")
|
||||||
(perl-mode all-the-icons-alltheicon "perl" :face all-the-icons-lorange)
|
(perl-mode all-the-icons-alltheicon "perl" :face all-the-icons-lorange)
|
||||||
(cperl-mode all-the-icons-alltheicon "perl" :face all-the-icons-lorange)
|
(cperl-mode all-the-icons-alltheicon "perl" :face all-the-icons-lorange)
|
||||||
(php-mode all-the-icons-fileicon "php" :face all-the-icons-lsilver)
|
(php-mode all-the-icons-fileicon "php" :face all-the-icons-lsilver)
|
||||||
(php-ts-mode all-the-icons-fileicon "php" :face all-the-icons-lsilver)
|
|
||||||
(phps-mode all-the-icons-fileicon "php" :face all-the-icons-lsilver)
|
|
||||||
(prolog-mode all-the-icons-alltheicon "prolog" :height 1.1 :face all-the-icons-lmaroon)
|
(prolog-mode all-the-icons-alltheicon "prolog" :height 1.1 :face all-the-icons-lmaroon)
|
||||||
(python-mode all-the-icons-alltheicon "python" :height 1.0 :face all-the-icons-dblue)
|
(python-mode all-the-icons-alltheicon "python" :height 1.0 :face all-the-icons-dblue)
|
||||||
(python-ts-mode all-the-icons-alltheicon "python" :height 1.0 :face all-the-icons-dblue)
|
(python-ts-mode all-the-icons-alltheicon "python" :height 1.0 :face all-the-icons-dblue)
|
||||||
|
@ -702,10 +695,6 @@ for performance sake.")
|
||||||
(scheme-mode all-the-icons-fileicon "scheme" :height 1.2 :face all-the-icons-red)
|
(scheme-mode all-the-icons-fileicon "scheme" :height 1.2 :face all-the-icons-red)
|
||||||
(swift-mode all-the-icons-alltheicon "swift" :height 1.0 :v-adjust -0.1 :face all-the-icons-green)
|
(swift-mode all-the-icons-alltheicon "swift" :height 1.0 :v-adjust -0.1 :face all-the-icons-green)
|
||||||
(svelte-mode all-the-icons-fileicon "svelte" :v-adjust 0.0 :face all-the-icons-red)
|
(svelte-mode all-the-icons-fileicon "svelte" :v-adjust 0.0 :face all-the-icons-red)
|
||||||
(ada-mode all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-blue)
|
|
||||||
(ada-ts-mode all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-blue)
|
|
||||||
(gpr-mode all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-green)
|
|
||||||
(gpr-ts-mode all-the-icons-fileicon "ada" :v-adjust 0.0 :face all-the-icons-green)
|
|
||||||
(c-mode all-the-icons-alltheicon "c-line" :face all-the-icons-blue)
|
(c-mode all-the-icons-alltheicon "c-line" :face all-the-icons-blue)
|
||||||
(c-ts-mode all-the-icons-alltheicon "c-line" :face all-the-icons-blue)
|
(c-ts-mode all-the-icons-alltheicon "c-line" :face all-the-icons-blue)
|
||||||
(c++-mode all-the-icons-alltheicon "cplusplus-line" :v-adjust -0.2 :face all-the-icons-blue)
|
(c++-mode all-the-icons-alltheicon "cplusplus-line" :v-adjust -0.2 :face all-the-icons-blue)
|
||||||
|
@ -784,6 +773,8 @@ for performance sake.")
|
||||||
(emms-tag-editor-mode all-the-icons-faicon "music" :face all-the-icons-silver)
|
(emms-tag-editor-mode all-the-icons-faicon "music" :face all-the-icons-silver)
|
||||||
(emms-playlist-mode all-the-icons-faicon "music" :face all-the-icons-silver)
|
(emms-playlist-mode all-the-icons-faicon "music" :face all-the-icons-silver)
|
||||||
(lilypond-mode all-the-icons-faicon "music" :face all-the-icons-green)
|
(lilypond-mode all-the-icons-faicon "music" :face all-the-icons-green)
|
||||||
|
(magik-session-mode all-the-icons-alltheicon "terminal" :face all-the-icons-blue)
|
||||||
|
(magik-cb-mode all-the-icons-faicon "book" :face all-the-icons-blue)
|
||||||
(meson-mode all-the-icons-fileicon "meson" :face all-the-icons-purple)
|
(meson-mode all-the-icons-fileicon "meson" :face all-the-icons-purple)
|
||||||
(man-common all-the-icons-fileicon "man-page" :face all-the-icons-blue)
|
(man-common all-the-icons-fileicon "man-page" :face all-the-icons-blue)
|
||||||
(ess-r-mode all-the-icons-fileicon "R" :face all-the-icons-lblue)))
|
(ess-r-mode all-the-icons-fileicon "R" :face all-the-icons-lblue)))
|
File diff suppressed because it is too large
Load diff
|
@ -138,11 +138,6 @@ Same as `byte-compile-file' but asynchronous.
|
||||||
(fn FILE)" t)
|
(fn FILE)" t)
|
||||||
(register-definition-prefixes "async-bytecomp" '("async-"))
|
(register-definition-prefixes "async-bytecomp" '("async-"))
|
||||||
|
|
||||||
|
|
||||||
;;; Generated autoloads from async-package.el
|
|
||||||
|
|
||||||
(register-definition-prefixes "async-package" '("async-package-"))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Generated autoloads from dired-async.el
|
;;; Generated autoloads from dired-async.el
|
||||||
|
|
|
@ -60,33 +60,6 @@ all packages are always compiled asynchronously."
|
||||||
(defvar async-bytecomp-load-variable-regexp "\\`load-path\\'"
|
(defvar async-bytecomp-load-variable-regexp "\\`load-path\\'"
|
||||||
"The variable used by `async-inject-variables' when (re)compiling async.")
|
"The variable used by `async-inject-variables' when (re)compiling async.")
|
||||||
|
|
||||||
(defun async-bytecomp--file-to-comp-buffer (file-or-dir &optional quiet type)
|
|
||||||
(let ((bn (file-name-nondirectory file-or-dir))
|
|
||||||
(action-name (pcase type
|
|
||||||
('file "File")
|
|
||||||
('directory "Directory"))))
|
|
||||||
(if (file-exists-p async-byte-compile-log-file)
|
|
||||||
(let ((buf (get-buffer-create byte-compile-log-buffer))
|
|
||||||
(n 0))
|
|
||||||
(with-current-buffer buf
|
|
||||||
(goto-char (point-max))
|
|
||||||
(let ((inhibit-read-only t))
|
|
||||||
(insert-file-contents async-byte-compile-log-file)
|
|
||||||
(compilation-mode))
|
|
||||||
(display-buffer buf)
|
|
||||||
(delete-file async-byte-compile-log-file)
|
|
||||||
(unless quiet
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (re-search-forward "^.*:Error:" nil t)
|
|
||||||
(cl-incf n)))
|
|
||||||
(if (> n 0)
|
|
||||||
(message "Failed to compile %d files in directory `%s'" n bn)
|
|
||||||
(message "%s `%s' compiled asynchronously with warnings"
|
|
||||||
action-name bn)))))
|
|
||||||
(unless quiet
|
|
||||||
(message "%s `%s' compiled asynchronously with success" action-name bn)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun async-byte-recompile-directory (directory &optional quiet)
|
(defun async-byte-recompile-directory (directory &optional quiet)
|
||||||
"Compile all *.el files in DIRECTORY asynchronously.
|
"Compile all *.el files in DIRECTORY asynchronously.
|
||||||
|
@ -100,7 +73,26 @@ All *.elc files are systematically deleted before proceeding."
|
||||||
(load "async")
|
(load "async")
|
||||||
(let ((call-back
|
(let ((call-back
|
||||||
(lambda (&optional _ignore)
|
(lambda (&optional _ignore)
|
||||||
(async-bytecomp--file-to-comp-buffer directory quiet 'directory))))
|
(if (file-exists-p async-byte-compile-log-file)
|
||||||
|
(let ((buf (get-buffer-create byte-compile-log-buffer))
|
||||||
|
(n 0))
|
||||||
|
(with-current-buffer buf
|
||||||
|
(goto-char (point-max))
|
||||||
|
(let ((inhibit-read-only t))
|
||||||
|
(insert-file-contents async-byte-compile-log-file)
|
||||||
|
(compilation-mode))
|
||||||
|
(display-buffer buf)
|
||||||
|
(delete-file async-byte-compile-log-file)
|
||||||
|
(unless quiet
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (re-search-forward "^.*:Error:" nil t)
|
||||||
|
(cl-incf n)))
|
||||||
|
(if (> n 0)
|
||||||
|
(message "Failed to compile %d files in directory `%s'" n directory)
|
||||||
|
(message "Directory `%s' compiled asynchronously with warnings" directory)))))
|
||||||
|
(unless quiet
|
||||||
|
(message "Directory `%s' compiled asynchronously with success" directory))))))
|
||||||
(async-start
|
(async-start
|
||||||
`(lambda ()
|
`(lambda ()
|
||||||
(require 'bytecomp)
|
(require 'bytecomp)
|
||||||
|
@ -148,10 +140,13 @@ All *.elc files are systematically deleted before proceeding."
|
||||||
(memq cur-package (async-bytecomp--get-package-deps
|
(memq cur-package (async-bytecomp--get-package-deps
|
||||||
async-bytecomp-allowed-packages)))
|
async-bytecomp-allowed-packages)))
|
||||||
(progn
|
(progn
|
||||||
|
;; FIXME: Why do we use (eq cur-package 'async) once
|
||||||
|
;; and (string= cur-package "async") afterwards?
|
||||||
(when (eq cur-package 'async)
|
(when (eq cur-package 'async)
|
||||||
(fmakunbound 'async-byte-recompile-directory)
|
(fmakunbound 'async-byte-recompile-directory))
|
||||||
;; Add to `load-path' the latest version of async and
|
;; Add to `load-path' the latest version of async and
|
||||||
;; reload it when reinstalling async.
|
;; reload it when reinstalling async.
|
||||||
|
(when (string= cur-package "async")
|
||||||
(cl-pushnew pkg-dir load-path)
|
(cl-pushnew pkg-dir load-path)
|
||||||
(load "async-bytecomp"))
|
(load "async-bytecomp"))
|
||||||
;; `async-byte-recompile-directory' will add directory
|
;; `async-byte-recompile-directory' will add directory
|
||||||
|
@ -178,13 +173,28 @@ Same as `byte-compile-file' but asynchronous."
|
||||||
(interactive "fFile: ")
|
(interactive "fFile: ")
|
||||||
(let ((call-back
|
(let ((call-back
|
||||||
(lambda (&optional _ignore)
|
(lambda (&optional _ignore)
|
||||||
(async-bytecomp--file-to-comp-buffer file nil 'file))))
|
(let ((bn (file-name-nondirectory file)))
|
||||||
|
(if (file-exists-p async-byte-compile-log-file)
|
||||||
|
(let ((buf (get-buffer-create byte-compile-log-buffer))
|
||||||
|
start)
|
||||||
|
(with-current-buffer buf
|
||||||
|
(goto-char (setq start (point-max)))
|
||||||
|
(let ((inhibit-read-only t))
|
||||||
|
(insert-file-contents async-byte-compile-log-file)
|
||||||
|
(compilation-mode))
|
||||||
|
(display-buffer buf)
|
||||||
|
(delete-file async-byte-compile-log-file)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char start)
|
||||||
|
(if (re-search-forward "^.*:Error:" nil t)
|
||||||
|
(message "Failed to compile `%s'" bn)
|
||||||
|
(message "`%s' compiled asynchronously with warnings" bn)))))
|
||||||
|
(message "`%s' compiled asynchronously with success" bn))))))
|
||||||
(async-start
|
(async-start
|
||||||
`(lambda ()
|
`(lambda ()
|
||||||
(require 'bytecomp)
|
(require 'bytecomp)
|
||||||
,(async-inject-variables async-bytecomp-load-variable-regexp)
|
,(async-inject-variables async-bytecomp-load-variable-regexp)
|
||||||
(let ((default-directory ,(file-name-directory file))
|
(let ((default-directory ,(file-name-directory file)))
|
||||||
error-data)
|
|
||||||
(add-to-list 'load-path default-directory)
|
(add-to-list 'load-path default-directory)
|
||||||
(byte-compile-file ,file)
|
(byte-compile-file ,file)
|
||||||
(when (get-buffer byte-compile-log-buffer)
|
(when (get-buffer byte-compile-log-buffer)
|
|
@ -1,6 +1,6 @@
|
||||||
(define-package "async" "20240719.640" "Asynchronous processing in Emacs"
|
(define-package "async" "20240312.1716" "Asynchronous processing in Emacs"
|
||||||
'((emacs "24.4"))
|
'((emacs "24.4"))
|
||||||
:commit "93957f5b0f2ed22aeef02972de860fb9c45b4422" :authors
|
:commit "a368df08d34ae0c0a36fc3e90b1ecda252915257" :authors
|
||||||
'(("John Wiegley" . "jwiegley@gmail.com"))
|
'(("John Wiegley" . "jwiegley@gmail.com"))
|
||||||
:maintainers
|
:maintainers
|
||||||
'(("Thierry Volpiatto" . "thievol@posteo.net"))
|
'(("Thierry Volpiatto" . "thievol@posteo.net"))
|
|
@ -50,13 +50,6 @@ When this is nil child Emacs will hang forever when a user interaction
|
||||||
for password is required unless a password is stored in a \".authinfo\" file."
|
for password is required unless a password is stored in a \".authinfo\" file."
|
||||||
:type 'boolean)
|
:type 'boolean)
|
||||||
|
|
||||||
(defvar async-process-noquery-on-exit nil
|
|
||||||
"Used as the :noquery argument to `make-process'.
|
|
||||||
|
|
||||||
Intended to be let-bound around a call to `async-start' or
|
|
||||||
`async-start-process'. If non-nil, the child Emacs process will
|
|
||||||
be silently killed if the user exits the parent Emacs.")
|
|
||||||
|
|
||||||
(defvar async-debug nil)
|
(defvar async-debug nil)
|
||||||
(defvar async-send-over-pipe t)
|
(defvar async-send-over-pipe t)
|
||||||
(defvar async-in-child-emacs nil)
|
(defvar async-in-child-emacs nil)
|
||||||
|
@ -117,17 +110,14 @@ is returned unmodified."
|
||||||
collect elm))
|
collect elm))
|
||||||
(t object)))
|
(t object)))
|
||||||
|
|
||||||
(defvar async-inject-variables-exclude-regexps '("-syntax-table\\'")
|
|
||||||
"A list of regexps that `async-inject-variables' should ignore.")
|
|
||||||
|
|
||||||
(defun async-inject-variables
|
(defun async-inject-variables
|
||||||
(include-regexp &optional predicate exclude-regexp noprops)
|
(include-regexp &optional predicate exclude-regexp noprops)
|
||||||
"Return a `setq' form that replicates part of the calling environment.
|
"Return a `setq' form that replicates part of the calling environment.
|
||||||
|
|
||||||
It sets the value for every variable matching INCLUDE-REGEXP and
|
It sets the value for every variable matching INCLUDE-REGEXP and
|
||||||
also PREDICATE. It will not perform injection for any variable
|
also PREDICATE. It will not perform injection for any variable
|
||||||
matching EXCLUDE-REGEXP (if present) and variables matching one of
|
matching EXCLUDE-REGEXP (if present) or representing a `syntax-table'
|
||||||
`async-inject-variables-exclude-regexps'.
|
i.e. ending by \"-syntax-table\".
|
||||||
When NOPROPS is non nil it tries to strip out text properties of each
|
When NOPROPS is non nil it tries to strip out text properties of each
|
||||||
variable's value with `async-variables-noprops-function'.
|
variable's value with `async-variables-noprops-function'.
|
||||||
|
|
||||||
|
@ -146,16 +136,14 @@ It is intended to be used as follows:
|
||||||
,@(let (bindings)
|
,@(let (bindings)
|
||||||
(mapatoms
|
(mapatoms
|
||||||
(lambda (sym)
|
(lambda (sym)
|
||||||
(let ((sname (and (boundp sym) (symbol-name sym)))
|
(let* ((sname (and (boundp sym) (symbol-name sym)))
|
||||||
value)
|
(value (and sname (symbol-value sym))))
|
||||||
(when (and sname
|
(when (and sname
|
||||||
(or (null include-regexp)
|
(or (null include-regexp)
|
||||||
(string-match include-regexp sname))
|
(string-match include-regexp sname))
|
||||||
(or (null exclude-regexp)
|
(or (null exclude-regexp)
|
||||||
(not (string-match exclude-regexp sname)))
|
(not (string-match exclude-regexp sname)))
|
||||||
(cl-loop for re in async-inject-variables-exclude-regexps
|
(not (string-match "-syntax-table\\'" sname)))
|
||||||
never (string-match-p re sname)))
|
|
||||||
(setq value (symbol-value sym))
|
|
||||||
(unless (or (stringp value)
|
(unless (or (stringp value)
|
||||||
(memq value '(nil t))
|
(memq value '(nil t))
|
||||||
(numberp value)
|
(numberp value)
|
||||||
|
@ -438,8 +426,7 @@ working directory."
|
||||||
:name name
|
:name name
|
||||||
:buffer buf
|
:buffer buf
|
||||||
:stderr buf-err
|
:stderr buf-err
|
||||||
:command (cons program program-args)
|
:command (cons program program-args)))))
|
||||||
:noquery async-process-noquery-on-exit))))
|
|
||||||
(set-process-sentinel
|
(set-process-sentinel
|
||||||
(get-buffer-process buf-err)
|
(get-buffer-process buf-err)
|
||||||
(lambda (proc _change)
|
(lambda (proc _change)
|
|
@ -387,7 +387,6 @@ ESC or `q' to not overwrite any of the remaining files,
|
||||||
(dired-copy-preserve-time
|
(dired-copy-preserve-time
|
||||||
,dired-copy-preserve-time)
|
,dired-copy-preserve-time)
|
||||||
(dired-create-destination-dirs ',create-dir)
|
(dired-create-destination-dirs ',create-dir)
|
||||||
(dired-vc-rename-file ,dired-vc-rename-file)
|
|
||||||
auth-source-save-behavior)
|
auth-source-save-behavior)
|
||||||
(setq overwrite-backup-query nil)
|
(setq overwrite-backup-query nil)
|
||||||
;; Inline `backup-file' as long as it is not
|
;; Inline `backup-file' as long as it is not
|
|
@ -1,132 +0,0 @@
|
||||||
;;; async-package.el --- Fetch packages asynchronously -*- lexical-binding: t -*-
|
|
||||||
|
|
||||||
;; Copyright (C) 2014-2022 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
;; Author: Thierry Volpiatto <thievol@posteo.net>
|
|
||||||
|
|
||||||
;; Keywords: dired async byte-compile package
|
|
||||||
;; X-URL: https://github.com/jwiegley/emacs-async
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
|
||||||
;; it under the terms of the GNU General Public License as published by
|
|
||||||
;; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
|
|
||||||
;; This program is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
;; GNU General Public License for more details.
|
|
||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Provide the function `async-package-do-action' to
|
|
||||||
;; (re)install/upgrade packages asynchronously.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(eval-when-compile (require 'cl-lib))
|
|
||||||
(require 'async-bytecomp)
|
|
||||||
(require 'dired-async)
|
|
||||||
(require 'package)
|
|
||||||
|
|
||||||
(define-minor-mode async-package--modeline-mode
|
|
||||||
"Notify mode-line that an async process run."
|
|
||||||
:group 'async
|
|
||||||
:global t
|
|
||||||
:lighter (:eval (propertize (format " [%s async job Installing package(s)]"
|
|
||||||
(length (dired-async-processes
|
|
||||||
'async-pkg-install)))
|
|
||||||
'face 'async-package-message))
|
|
||||||
(unless async-package--modeline-mode
|
|
||||||
(let ((visible-bell t)) (ding))))
|
|
||||||
|
|
||||||
(defface async-package-message
|
|
||||||
'((t (:foreground "yellow")))
|
|
||||||
"Face used for mode-line message.")
|
|
||||||
|
|
||||||
(defun async-package-do-action (action packages error-file)
|
|
||||||
"Execute ACTION asynchronously on PACKAGES.
|
|
||||||
Argument ACTION can be one of \\='install, \\='upgrade, \\='reinstall.
|
|
||||||
Argument PACKAGES is a list of packages (symbols).
|
|
||||||
Argument ERROR-FILE is the file where errors are logged, if some."
|
|
||||||
(require 'async-bytecomp)
|
|
||||||
(let ((fn (pcase action
|
|
||||||
('install 'package-install)
|
|
||||||
('upgrade 'package-upgrade)
|
|
||||||
('reinstall 'package-reinstall)))
|
|
||||||
(action-string (pcase action
|
|
||||||
('install "Installing")
|
|
||||||
('upgrade "Upgrading")
|
|
||||||
('reinstall "Reinstalling"))))
|
|
||||||
(message "%s %s package(s)..." action-string (length packages))
|
|
||||||
(process-put
|
|
||||||
(async-start
|
|
||||||
`(lambda ()
|
|
||||||
(require 'bytecomp)
|
|
||||||
(setq package-archives ',package-archives
|
|
||||||
package-pinned-packages ',package-pinned-packages
|
|
||||||
package-archive-contents ',package-archive-contents
|
|
||||||
package-alist ',package-alist
|
|
||||||
load-path ',load-path)
|
|
||||||
(prog1
|
|
||||||
(condition-case err
|
|
||||||
(mapc ',fn ',packages)
|
|
||||||
(error
|
|
||||||
(with-temp-file ,error-file
|
|
||||||
(insert
|
|
||||||
(format
|
|
||||||
"%S:\n Please refresh package list before %s"
|
|
||||||
err ,action-string)))))
|
|
||||||
(let (error-data)
|
|
||||||
(when (get-buffer byte-compile-log-buffer)
|
|
||||||
(setq error-data (with-current-buffer byte-compile-log-buffer
|
|
||||||
(buffer-substring-no-properties
|
|
||||||
(point-min) (point-max))))
|
|
||||||
(unless (string= error-data "")
|
|
||||||
(with-temp-file ,async-byte-compile-log-file
|
|
||||||
(erase-buffer)
|
|
||||||
(insert error-data)))))))
|
|
||||||
(lambda (result)
|
|
||||||
(if (file-exists-p error-file)
|
|
||||||
(let ((buf (find-file-noselect error-file)))
|
|
||||||
(pop-to-buffer
|
|
||||||
buf '(nil . ((window-height . fit-window-to-buffer))))
|
|
||||||
(special-mode)
|
|
||||||
(delete-file error-file)
|
|
||||||
(async-package--modeline-mode -1))
|
|
||||||
(when result
|
|
||||||
(let ((pkgs (if (listp result) result (list result))))
|
|
||||||
(when (eq action 'install)
|
|
||||||
(customize-save-variable
|
|
||||||
'package-selected-packages
|
|
||||||
(delete-dups (append pkgs package-selected-packages))))
|
|
||||||
(package-load-all-descriptors) ; refresh package-alist.
|
|
||||||
(mapc #'package-activate pkgs) ; load packages.
|
|
||||||
(async-package--modeline-mode -1)
|
|
||||||
(message "%s %s packages done" action-string (length packages))
|
|
||||||
(run-with-timer
|
|
||||||
0.1 nil
|
|
||||||
(lambda (lst str)
|
|
||||||
(dired-async-mode-line-message
|
|
||||||
"%s %d package(s) done"
|
|
||||||
'async-package-message
|
|
||||||
str (length lst)))
|
|
||||||
packages action-string)
|
|
||||||
(when (file-exists-p async-byte-compile-log-file)
|
|
||||||
(let ((buf (get-buffer-create byte-compile-log-buffer)))
|
|
||||||
(with-current-buffer buf
|
|
||||||
(goto-char (point-max))
|
|
||||||
(let ((inhibit-read-only t))
|
|
||||||
(insert-file-contents async-byte-compile-log-file)
|
|
||||||
(compilation-mode))
|
|
||||||
(display-buffer buf)
|
|
||||||
(delete-file async-byte-compile-log-file)))))))))
|
|
||||||
'async-pkg-install t)
|
|
||||||
(async-package--modeline-mode 1)))
|
|
||||||
|
|
||||||
(provide 'async-package)
|
|
||||||
|
|
||||||
;;; async-package.el ends here
|
|
|
@ -1,14 +1,12 @@
|
||||||
;;; centaur-tabs-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
|
;;; centaur-tabs-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
|
||||||
;; Generated by the `loaddefs-generate' function.
|
;;
|
||||||
|
|
||||||
;; This file is part of GNU Emacs.
|
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
|
(add-to-list 'load-path (directory-file-name
|
||||||
|
(or (file-name-directory #$) (car load-path))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;### (autoloads nil "centaur-tabs" "centaur-tabs.el" (0 0 0 0))
|
||||||
;;; Generated autoloads from centaur-tabs.el
|
;;; Generated autoloads from centaur-tabs.el
|
||||||
|
|
||||||
(autoload 'centaur-tabs-local-mode "centaur-tabs" "\
|
(autoload 'centaur-tabs-local-mode "centaur-tabs" "\
|
||||||
|
@ -20,7 +18,8 @@ the tab bar. The tab bar is locally hidden otherwise. When turned
|
||||||
off, if a local header line is hidden or the tab bar is locally
|
off, if a local header line is hidden or the tab bar is locally
|
||||||
hidden, it is shown again. Signal an error if Centaur-Tabs mode is off.
|
hidden, it is shown again. Signal an error if Centaur-Tabs mode is off.
|
||||||
|
|
||||||
(fn &optional ARG)" t)
|
\(fn &optional ARG)" t nil)
|
||||||
|
|
||||||
(defvar centaur-tabs-mode nil "\
|
(defvar centaur-tabs-mode nil "\
|
||||||
Non-nil if Centaur-Tabs mode is enabled.
|
Non-nil if Centaur-Tabs mode is enabled.
|
||||||
See the `centaur-tabs-mode' command
|
See the `centaur-tabs-mode' command
|
||||||
|
@ -28,7 +27,9 @@ for a description of this minor mode.
|
||||||
Setting this variable directly does not take effect;
|
Setting this variable directly does not take effect;
|
||||||
either customize it (see the info node `Easy Customization')
|
either customize it (see the info node `Easy Customization')
|
||||||
or call the function `centaur-tabs-mode'.")
|
or call the function `centaur-tabs-mode'.")
|
||||||
|
|
||||||
(custom-autoload 'centaur-tabs-mode "centaur-tabs" nil)
|
(custom-autoload 'centaur-tabs-mode "centaur-tabs" nil)
|
||||||
|
|
||||||
(autoload 'centaur-tabs-mode "centaur-tabs" "\
|
(autoload 'centaur-tabs-mode "centaur-tabs" "\
|
||||||
Toggle display of a tab bar in the header line.
|
Toggle display of a tab bar in the header line.
|
||||||
With prefix argument ARG, turn on if positive, otherwise off.
|
With prefix argument ARG, turn on if positive, otherwise off.
|
||||||
|
@ -36,50 +37,67 @@ Returns non-nil if the new state is enabled.
|
||||||
|
|
||||||
\\{centaur-tabs-mode-map}
|
\\{centaur-tabs-mode-map}
|
||||||
|
|
||||||
(fn &optional ARG)" t)
|
\(fn &optional ARG)" t nil)
|
||||||
|
|
||||||
(register-definition-prefixes "centaur-tabs" '("centaur-tabs-"))
|
(register-definition-prefixes "centaur-tabs" '("centaur-tabs-"))
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
|
;;;### (autoloads nil "centaur-tabs-elements" "centaur-tabs-elements.el"
|
||||||
|
;;;;;; (0 0 0 0))
|
||||||
;;; Generated autoloads from centaur-tabs-elements.el
|
;;; Generated autoloads from centaur-tabs-elements.el
|
||||||
|
|
||||||
(register-definition-prefixes "centaur-tabs-elements" '("centaur-tabs-"))
|
(register-definition-prefixes "centaur-tabs-elements" '("cent"))
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
|
;;;### (autoloads nil "centaur-tabs-functions" "centaur-tabs-functions.el"
|
||||||
|
;;;;;; (0 0 0 0))
|
||||||
;;; Generated autoloads from centaur-tabs-functions.el
|
;;; Generated autoloads from centaur-tabs-functions.el
|
||||||
|
|
||||||
(autoload 'centaur-tabs-backward "centaur-tabs-functions" "\
|
(autoload 'centaur-tabs-backward "centaur-tabs-functions" "\
|
||||||
Select the previous available tab.
|
Select the previous available tab.
|
||||||
Depend on the setting of the option `centaur-tabs-cycle-scope'." t)
|
Depend on the setting of the option `centaur-tabs-cycle-scope'." t nil)
|
||||||
|
|
||||||
(autoload 'centaur-tabs-forward "centaur-tabs-functions" "\
|
(autoload 'centaur-tabs-forward "centaur-tabs-functions" "\
|
||||||
Select the next available tab.
|
Select the next available tab.
|
||||||
Depend on the setting of the option `centaur-tabs-cycle-scope'." t)
|
Depend on the setting of the option `centaur-tabs-cycle-scope'." t nil)
|
||||||
|
|
||||||
(autoload 'centaur-tabs-backward-group "centaur-tabs-functions" "\
|
(autoload 'centaur-tabs-backward-group "centaur-tabs-functions" "\
|
||||||
Go to selected tab in the previous available group." t)
|
Go to selected tab in the previous available group." t nil)
|
||||||
|
|
||||||
(autoload 'centaur-tabs-forward-group "centaur-tabs-functions" "\
|
(autoload 'centaur-tabs-forward-group "centaur-tabs-functions" "\
|
||||||
Go to selected tab in the next available group." t)
|
Go to selected tab in the next available group." t nil)
|
||||||
|
|
||||||
(autoload 'centaur-tabs-backward-tab "centaur-tabs-functions" "\
|
(autoload 'centaur-tabs-backward-tab "centaur-tabs-functions" "\
|
||||||
Select the previous visible tab." t)
|
Select the previous visible tab." t nil)
|
||||||
|
|
||||||
(autoload 'centaur-tabs-forward-tab "centaur-tabs-functions" "\
|
(autoload 'centaur-tabs-forward-tab "centaur-tabs-functions" "\
|
||||||
Select the next visible tab." t)
|
Select the next visible tab." t nil)
|
||||||
|
|
||||||
(register-definition-prefixes "centaur-tabs-functions" '("centaur-tabs-"))
|
(register-definition-prefixes "centaur-tabs-functions" '("centaur-tabs-"))
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
|
;;;### (autoloads nil "centaur-tabs-interactive" "centaur-tabs-interactive.el"
|
||||||
|
;;;;;; (0 0 0 0))
|
||||||
;;; Generated autoloads from centaur-tabs-interactive.el
|
;;; Generated autoloads from centaur-tabs-interactive.el
|
||||||
|
|
||||||
(autoload 'centaur-tabs-counsel-switch-group "centaur-tabs-interactive" "\
|
(autoload 'centaur-tabs-counsel-switch-group "centaur-tabs-interactive" "\
|
||||||
Display a list of current buffer groups using Counsel." t)
|
Display a list of current buffer groups using Counsel." t nil)
|
||||||
|
|
||||||
(register-definition-prefixes "centaur-tabs-interactive" '("centaur-tabs-"))
|
(register-definition-prefixes "centaur-tabs-interactive" '("centaur-tabs-"))
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
;;; End of scraped data
|
;;;### (autoloads nil nil ("centaur-tabs-pkg.el") (0 0 0 0))
|
||||||
|
|
||||||
(provide 'centaur-tabs-autoloads)
|
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
;; version-control: never
|
;; version-control: never
|
||||||
;; no-byte-compile: t
|
;; no-byte-compile: t
|
||||||
;; no-update-autoloads: t
|
;; no-update-autoloads: t
|
||||||
;; no-native-compile: t
|
;; coding: utf-8
|
||||||
;; coding: utf-8-emacs-unix
|
|
||||||
;; End:
|
;; End:
|
||||||
|
|
||||||
;;; centaur-tabs-autoloads.el ends here
|
;;; centaur-tabs-autoloads.el ends here
|
865
code/elpa/centaur-tabs-20230607.1501/centaur-tabs-elements.el
Normal file
865
code/elpa/centaur-tabs-20230607.1501/centaur-tabs-elements.el
Normal file
|
@ -0,0 +1,865 @@
|
||||||
|
;;; centaur-tabs-elements.el --- centaur-tabs visual components and customizations -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Copyright (C) 2019-2020 Emmanuel Bustos
|
||||||
|
;; Package-Requires: ((emacs "24.4") (powerline "2.4") (cl-lib "0.5"))
|
||||||
|
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; This program is free software; you can redistribute it and/or
|
||||||
|
;; modify it under the terms of the GNU General Public License as
|
||||||
|
;; published by the Free Software Foundation; either version 2, or
|
||||||
|
;; (at your option) any later version.
|
||||||
|
;;
|
||||||
|
;; This program is distributed in the hope that it will be useful,
|
||||||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
;; General Public License for more details.
|
||||||
|
;;
|
||||||
|
;; You should have received a copy of the GNU General Public License
|
||||||
|
;; along with this program; see the file COPYING. If not, write to
|
||||||
|
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
||||||
|
;; Floor, Boston, MA 02110-1301, USA.
|
||||||
|
;;
|
||||||
|
;;; Commentary:
|
||||||
|
;; This file contains the visual components of centaur-tabs
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
;;
|
||||||
|
;;; Requires
|
||||||
|
;;
|
||||||
|
(require 'color)
|
||||||
|
(require 'powerline)
|
||||||
|
;;; Faces
|
||||||
|
;;
|
||||||
|
(defface centaur-tabs-default
|
||||||
|
'((t
|
||||||
|
(:background "black" :foreground "black")))
|
||||||
|
"Default face used in the tab bar."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-unselected
|
||||||
|
'((t
|
||||||
|
(:background "#3D3C3D" :foreground "grey50")))
|
||||||
|
"Face used for unselected tabs."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-selected
|
||||||
|
'((t (:background "#31343E" :foreground "white")))
|
||||||
|
"Face used for the selected tab."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-unselected-modified
|
||||||
|
'((t
|
||||||
|
(:background "#3D3C3D" :foreground "grey50")))
|
||||||
|
"Face used for unselected-modified tabs."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-selected-modified
|
||||||
|
'((t (:background "#31343E" :foreground "white")))
|
||||||
|
"Face used for the selected-modified tab."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-close-unselected
|
||||||
|
'((t
|
||||||
|
(:inherit centaur-tabs-unselected)))
|
||||||
|
"Face used for unselected close button."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-close-selected
|
||||||
|
'((t (:inherit centaur-tabs-selected)))
|
||||||
|
"Face used for selected close button."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-name-mouse-face
|
||||||
|
'((t nil))
|
||||||
|
"Face used for tab name when hovered with the mouse."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-close-mouse-face
|
||||||
|
'((t (:inherit underline)))
|
||||||
|
"Face used for close button when hovered with the mouse."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-modified-marker-selected
|
||||||
|
`((t (:inherit centaur-tabs-selected)))
|
||||||
|
"Face used for selected modified marker."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-modified-marker-unselected
|
||||||
|
`((t (:inherit centaur-tabs-unselected)))
|
||||||
|
"Face used for unselected modified marker."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-active-bar-face
|
||||||
|
'((t (:background "cyan")))
|
||||||
|
"Face used for selected tab bar."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-jump-identifier-selected
|
||||||
|
'((t (:inherit centaur-tabs-modified-marker-selected :weight extra-bold)))
|
||||||
|
"Face used for selected tab identifiers when centaur-tabs-ace-jump is invoked."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-jump-identifier-unselected
|
||||||
|
'((t (:inherit centaur-tabs-modified-marker-unselected :weight extra-bold)))
|
||||||
|
"Face used for unselected tab identifiers when centaur-tabs-ace-jump is invoked."
|
||||||
|
:group 'centaur-tabs)
|
||||||
|
|
||||||
|
(defface centaur-tabs-dim-buffer-face
|
||||||
|
'((t (:foreground "gray40")))
|
||||||
|
"Face for the buffer when centaur-tabs-ace-jump is invoked.")
|
||||||
|
|
||||||
|
;;; Tabs' display line
|
||||||
|
;;
|
||||||
|
(defvar centaur-tabs-display-line
|
||||||
|
(if (boundp 'tab-line-format)
|
||||||
|
'tab-line
|
||||||
|
'header-line))
|
||||||
|
|
||||||
|
(defvar centaur-tabs-display-line-format
|
||||||
|
(if (boundp 'tab-line-format)
|
||||||
|
'tab-line-format
|
||||||
|
'header-line-format))
|
||||||
|
|
||||||
|
;;; Tabs' characteristics
|
||||||
|
;;
|
||||||
|
(defcustom centaur-tabs-style "bar"
|
||||||
|
"The style of tab."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-label-fixed-length 0
|
||||||
|
"Fixed length of label. Set to 0 if dynamic."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'int)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-background-color
|
||||||
|
(face-background 'centaur-tabs-default nil 'default)
|
||||||
|
"*Background color of the tab bar.
|
||||||
|
By default, use the background color specified for the
|
||||||
|
`centaur-tabs-default' face (or inherited from another face), or the
|
||||||
|
background color of the `default' face otherwise."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'face)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-height 22
|
||||||
|
"The height of tab."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'int)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-bar-height (+ 8 centaur-tabs-height)
|
||||||
|
"The height of bar."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'int)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-mouse-pointer 'hand
|
||||||
|
"Cursor to display when hovering the tabs.
|
||||||
|
Default is 'hand. The following scopes are possible:
|
||||||
|
- arrow
|
||||||
|
- hand
|
||||||
|
- vdrag
|
||||||
|
- hdrag
|
||||||
|
- modeline
|
||||||
|
- hourglass"
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'variable)
|
||||||
|
|
||||||
|
;;; Icons
|
||||||
|
;;
|
||||||
|
(defcustom centaur-tabs-set-icons nil
|
||||||
|
"When non nil, display an icon based on `centaur-tabs-icon-type' alongside the tab name."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-icon-type (and centaur-tabs-set-icons
|
||||||
|
(or (require 'all-the-icons nil t)
|
||||||
|
(require 'nerd-icons nil t)))
|
||||||
|
"Icon type. It should be one of `all-the-icons' and `nerd-icons'."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'symbol
|
||||||
|
:set
|
||||||
|
(lambda (k v)
|
||||||
|
(pcase v
|
||||||
|
('all-the-icons
|
||||||
|
(unless (require 'all-the-icons nil t)
|
||||||
|
(setq v nil)))
|
||||||
|
('nerd-icons
|
||||||
|
(unless (require 'nerd-icons nil t)
|
||||||
|
(setq v nil)))
|
||||||
|
(type
|
||||||
|
(if (require 'all-the-icons nil t)
|
||||||
|
(setq v 'all-the-icons)
|
||||||
|
(setq v nil))))
|
||||||
|
(set k v)))
|
||||||
|
|
||||||
|
(defvar centaur-tabs-icon-scale-factor
|
||||||
|
1.0
|
||||||
|
"The base scale factor for the `height' face property of tab icons.")
|
||||||
|
|
||||||
|
(defvar centaur-tabs-icon-v-adjust
|
||||||
|
0.01
|
||||||
|
"The vertical adjust for tab icons.")
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-gray-out-icons nil
|
||||||
|
"When non nil, enable gray icons for unselected buffer."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type '(choice :tag "Gray out icons for unselected..."
|
||||||
|
(const :tag "Buffer" buffer)))
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-plain-icons nil
|
||||||
|
"When non nil, tab icons' color will be the same as tabs' foreground color."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defun centaur-tabs--icon-for-file (file &rest args)
|
||||||
|
"Get the formatted icon for FILE.
|
||||||
|
ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties."
|
||||||
|
(pcase centaur-tabs-icon-type
|
||||||
|
('all-the-icons (apply #'all-the-icons-icon-for-file file args))
|
||||||
|
('nerd-icons (apply #'nerd-icons-icon-for-file file args))))
|
||||||
|
|
||||||
|
(defun centaur-tabs--icon-for-mode (mode &rest args)
|
||||||
|
"Get the formatted icon for MODE.
|
||||||
|
ARG-OVERRIDES should be a plist containining `:height',
|
||||||
|
`:v-adjust' or `:face' properties like in the normal icon
|
||||||
|
inserting functions."
|
||||||
|
(pcase centaur-tabs-icon-type
|
||||||
|
('all-the-icons (apply #'all-the-icons-icon-for-mode mode args))
|
||||||
|
('nerd-icons (apply #'nerd-icons-icon-for-mode mode args))))
|
||||||
|
|
||||||
|
(defun centaur-tabs--auto-mode-match? (&optional file)
|
||||||
|
"Whether or not FILE's `major-mode' match against its `auto-mode-alist'."
|
||||||
|
(pcase centaur-tabs-icon-type
|
||||||
|
('all-the-icons (apply #'all-the-icons-auto-mode-match? file))
|
||||||
|
('nerd-icons (apply #'nerd-icons-auto-mode-match? file))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-icon (tab face selected)
|
||||||
|
"Generate icon for TAB using FACE's background.
|
||||||
|
If icon gray out option enabled, gray out icon if not SELECTED."
|
||||||
|
(if centaur-tabs-icon-type
|
||||||
|
(with-current-buffer (car tab)
|
||||||
|
(let* ((icon
|
||||||
|
(if (and (buffer-file-name)
|
||||||
|
(centaur-tabs--auto-mode-match?))
|
||||||
|
(centaur-tabs--icon-for-file
|
||||||
|
(file-name-nondirectory (buffer-file-name))
|
||||||
|
:v-adjust centaur-tabs-icon-v-adjust
|
||||||
|
:height centaur-tabs-icon-scale-factor)
|
||||||
|
(centaur-tabs--icon-for-mode
|
||||||
|
major-mode
|
||||||
|
:v-adjust centaur-tabs-icon-v-adjust
|
||||||
|
:height centaur-tabs-icon-scale-factor)))
|
||||||
|
(background (face-background face nil 'default))
|
||||||
|
(inactive (cond ((and (not selected)
|
||||||
|
(eq centaur-tabs-gray-out-icons 'buffer))
|
||||||
|
(face-foreground 'mode-line-inactive nil 'default))
|
||||||
|
(centaur-tabs-plain-icons
|
||||||
|
(face-foreground 'centaur-tabs-selected nil 'default))
|
||||||
|
(t 'unspecified)))
|
||||||
|
(underline (and (eq (if (display-graphic-p) centaur-tabs-set-bar) 'under)
|
||||||
|
(face-attribute face :underline)))
|
||||||
|
(overline (and (eq (if (display-graphic-p) centaur-tabs-set-bar) 'over)
|
||||||
|
(face-attribute face :overline))))
|
||||||
|
(if (stringp icon)
|
||||||
|
(progn
|
||||||
|
(propertize icon 'face `(:inherit ,(get-text-property 0 'face icon)
|
||||||
|
:foreground ,inactive
|
||||||
|
:background ,background
|
||||||
|
:underline ,underline
|
||||||
|
:overline ,overline)))
|
||||||
|
"")))
|
||||||
|
""))
|
||||||
|
|
||||||
|
;;; Ace-window style tab switching
|
||||||
|
;;
|
||||||
|
(defcustom centaur-tabs-show-jump-identifier 'prompted
|
||||||
|
"Whether to show the tab identifier for centaur-tabs-ace-jump.
|
||||||
|
It has 3 options:
|
||||||
|
- 'nil, never show the jump identifier.
|
||||||
|
- 'prompted, only show it when using centaur-tabs-ace-jump.
|
||||||
|
- 'always, always show it regardless of the status."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type '(choice :tag "show identifier when..."
|
||||||
|
(const :tag "Never" nil)
|
||||||
|
(const :tag "Only when prompted" prompted)
|
||||||
|
(const :tag "Always" always)))
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-ace-jump-dim-buffer t
|
||||||
|
"Whether to dim the current buffer when centaur-ace-jump is activated.")
|
||||||
|
|
||||||
|
(defvar centaur-tabs-ace-jump-keys
|
||||||
|
'(?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)
|
||||||
|
"Buffer jump keys used by centaur-tabs-ace-jump.")
|
||||||
|
|
||||||
|
(defvar centuar-tabs-ace-dispatch-alist
|
||||||
|
'((?q exit "Exit")
|
||||||
|
(?\C-g exit "Exit")
|
||||||
|
(?j jump-to-tab "Jump to tab")
|
||||||
|
(?x close-tab "Close tab")
|
||||||
|
(?s swap-tab "Swap tab")
|
||||||
|
(?\[ backward-group "Previous group")
|
||||||
|
(?\] forward-group "Next group")
|
||||||
|
(?? show-help "Show dispatch help"))
|
||||||
|
"Action keys used by centaur-tabs-ace-jump.
|
||||||
|
The value of each element must be in the form:
|
||||||
|
\(key keyword docstring), where keyword must be one of the follows:
|
||||||
|
\(exit, jump-to-tab, close-tab, swap-tab, backward-group,
|
||||||
|
forward-group, show-help).")
|
||||||
|
|
||||||
|
;;; Close buttons, modified marker and edges' margins
|
||||||
|
;;
|
||||||
|
(defcustom centaur-tabs-set-close-button t
|
||||||
|
"When non nil, display a clickable close button on the right side of the tabs."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-set-left-close-button nil
|
||||||
|
"When non nil, display a clickable close button on the left side of the tabs."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-close-button (make-string 1 #x00D7)
|
||||||
|
"Display appearance of the close buttons, if enabled."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-set-modified-marker nil
|
||||||
|
"When non nil, display a marker when the buffer is modified."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-modified-marker (make-string 1 #x23FA)
|
||||||
|
"Display appearance of the modified marker, if enabled."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-left-edge-margin " "
|
||||||
|
"Text to display at the left edge of the tabs, or nil for no added margin."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-right-edge-margin " "
|
||||||
|
"Text to display at the right edge of the tabs, or nil for no added margin."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
;;; Selected tab bar
|
||||||
|
;;
|
||||||
|
(defcustom centaur-tabs-set-bar nil
|
||||||
|
"When non nil, display a bar to show the currently selected tab.
|
||||||
|
There are three options:
|
||||||
|
- 'left: displays the bar at the left of the currently selected tab.
|
||||||
|
- 'under: displays the bar under the currently selected tab.
|
||||||
|
- 'over: displays the bar over the currently selected tab."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type '(choice :tag "Display bar at..."
|
||||||
|
(const :tag "Put bar on the left" left)
|
||||||
|
(const :tag "Put bar as an underline" under)
|
||||||
|
(const :tag "Put bar as an overline" over)))
|
||||||
|
|
||||||
|
(defun centaur-tabs--make-xpm (face width height)
|
||||||
|
"Create an XPM bitmap via FACE WIDTH and HEIGHT.
|
||||||
|
Taken from `doom-modeline'."
|
||||||
|
(when (and (display-graphic-p)
|
||||||
|
(image-type-available-p 'xpm))
|
||||||
|
(propertize
|
||||||
|
" " 'display
|
||||||
|
(let ((data (make-list height (make-list width 1)))
|
||||||
|
(color (or (face-background face nil t) "None")))
|
||||||
|
(ignore-errors
|
||||||
|
(create-image
|
||||||
|
(concat
|
||||||
|
(format
|
||||||
|
"/* XPM */\nstatic char * percent[] = {\n\"%i %i 2 1\",\n\". c %s\",\n\" c %s\","
|
||||||
|
(length (car data)) (length data) color color)
|
||||||
|
(apply #'concat
|
||||||
|
(cl-loop with idx = 0
|
||||||
|
with len = (length data)
|
||||||
|
for dl in data
|
||||||
|
do (cl-incf idx)
|
||||||
|
collect
|
||||||
|
(concat
|
||||||
|
"\""
|
||||||
|
(cl-loop for d in dl
|
||||||
|
if (= d 0) collect (string-to-char " ")
|
||||||
|
else collect (string-to-char "."))
|
||||||
|
(if (eq idx len) "\"};" "\",\n")))))
|
||||||
|
'xpm t :ascent 'center))))))
|
||||||
|
|
||||||
|
(defvar centaur-tabs-active-bar
|
||||||
|
(centaur-tabs--make-xpm 'centaur-tabs-active-bar-face
|
||||||
|
2
|
||||||
|
centaur-tabs-bar-height))
|
||||||
|
|
||||||
|
;;; Navigation buttons
|
||||||
|
;;
|
||||||
|
(defcustom centaur-tabs-show-navigation-buttons nil
|
||||||
|
"When non-nil, show the buttons for backward/forward tabs."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-down-tab-text " ▾ "
|
||||||
|
"Text icon to show in the down button tab."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-backward-tab-text " ⏴ "
|
||||||
|
"Text icon to show in the backward button tab."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-forward-tab-text " ⏵ "
|
||||||
|
"Text icon to show in the forward button tab."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-show-count nil
|
||||||
|
"When non-nil, show the current index and count of tabs in the current group."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
;;; New tab button
|
||||||
|
;;
|
||||||
|
(defcustom centaur-tabs-show-new-tab-button t
|
||||||
|
"When non-nil, show the button to create a new tab."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom centaur-tabs-new-tab-text " + "
|
||||||
|
"Text icon to show in the new-tab button."
|
||||||
|
:group 'centaur-tabs
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
;;; Separators
|
||||||
|
;;
|
||||||
|
(defvar centaur-tabs-style-left nil)
|
||||||
|
(defvar centaur-tabs-style-right nil)
|
||||||
|
|
||||||
|
(defvar ns-use-srgb-colorspace)
|
||||||
|
|
||||||
|
(defvar centaur-tabs-image-apple-rgb
|
||||||
|
(and (eq (window-system) 'ns)
|
||||||
|
ns-use-srgb-colorspace
|
||||||
|
(< 11
|
||||||
|
(string-to-number
|
||||||
|
(and (string-match "darwin\\([0-9]+\\)" system-configuration)
|
||||||
|
(match-string-no-properties 1 system-configuration)))))
|
||||||
|
"Boolean variable to determine whether to use Apple RGB colorspace.
|
||||||
|
used to render images.
|
||||||
|
|
||||||
|
t on macOS 10.7+ and `ns-use-srgb-colorspace' is t, nil otherwise.
|
||||||
|
|
||||||
|
This variable is automatically set, there's no need to modify it.")
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-interpolate (color1 color2)
|
||||||
|
"Interpolate between COLOR1 and COLOR2.
|
||||||
|
|
||||||
|
COLOR1 and COLOR2 must be supplied as hex strings with a leading #."
|
||||||
|
(let* ((c1 (color-name-to-rgb color1))
|
||||||
|
(c2 (color-name-to-rgb color2))
|
||||||
|
(red (/ (+ (nth 0 c1) (nth 0 c2)) 2))
|
||||||
|
(green (/ (+ (nth 1 c1) (nth 1 c2)) 2))
|
||||||
|
(blue (/ (+ (nth 2 c1) (nth 2 c2)) 2)))
|
||||||
|
(color-rgb-to-hex red green blue)))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-color-xyz-to-apple-rgb (X Y Z)
|
||||||
|
"Convert CIE X Y Z colors to Apple RGB color space."
|
||||||
|
(let ((r (+ (* 3.2404542 X) (* -1.5371385 Y) (* -0.4985314 Z)))
|
||||||
|
(g (+ (* -0.9692660 X) (* 1.8760108 Y) (* 0.0415560 Z)))
|
||||||
|
(b (+ (* 0.0556434 X) (* -0.2040259 Y) (* 1.0572252 Z))))
|
||||||
|
(list (expt r (/ 1.8)) (expt g (/ 1.8)) (expt b (/ 1.8)))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-color-srgb-to-apple-rgb (red green blue)
|
||||||
|
"Convert RED GREEN BLUE colors from sRGB color space to Apple RGB.
|
||||||
|
RED, GREEN and BLUE should be between 0.0 and 1.0, inclusive."
|
||||||
|
(apply #'centaur-tabs-separator-color-xyz-to-apple-rgb (color-srgb-to-xyz red green blue)))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-hex-color (color)
|
||||||
|
"Get the hexadecimal value of COLOR."
|
||||||
|
(when color
|
||||||
|
(let ((srgb-color (color-name-to-rgb color)))
|
||||||
|
(if centaur-tabs-image-apple-rgb
|
||||||
|
(apply #'color-rgb-to-hex (apply #'centaur-tabs-separator-color-srgb-to-apple-rgb srgb-color))
|
||||||
|
(apply #'color-rgb-to-hex srgb-color)))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-pattern (lst)
|
||||||
|
"Turn LST into an infinite pattern."
|
||||||
|
(when lst
|
||||||
|
(let ((pattern (cl-copy-list lst)))
|
||||||
|
(setcdr (last pattern) pattern))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-pattern-to-string (pattern)
|
||||||
|
"Convert a PATTERN into a string that can be used in an XPM."
|
||||||
|
(concat "\"" (mapconcat #'number-to-string pattern "") "\","))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-reverse-pattern (pattern)
|
||||||
|
"Reverse each line in PATTERN."
|
||||||
|
(cl-mapcar 'reverse pattern))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-row-pattern (fill total &optional fade)
|
||||||
|
"Make a list that has FILL 0s out of TOTAL 1s with FADE 2s to the right of the fill."
|
||||||
|
(unless fade
|
||||||
|
(setq fade 0))
|
||||||
|
(let ((fill (min fill total))
|
||||||
|
(fade (min fade (max (- total fill) 0))))
|
||||||
|
(append (make-list fill 0)
|
||||||
|
(make-list fade 2)
|
||||||
|
(make-list (- total fill fade) 1))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-pattern-bindings-body (patterns height-exp pattern-height-sym
|
||||||
|
second-pattern-height-sym)
|
||||||
|
"Create let-var bindings and a function body from PATTERNS.
|
||||||
|
The `car' and `cdr' parts of the result can be passed to the
|
||||||
|
function `centaur-tabs-separator-wrap-defun' as its `let-vars'
|
||||||
|
and `body' arguments,respectively. HEIGHT-EXP is an expression
|
||||||
|
calculating the image height and it should contain a free variable `height'.
|
||||||
|
PATTERN-HEIGHT-SYM and SECOND-PATTERN-HEIGHT-SYM are symbols used
|
||||||
|
for let-var binding variables."
|
||||||
|
(let* ((pattern (centaur-tabs-separator-pattern (cl-mapcar 'centaur-tabs-separator-pattern-to-string (car patterns))))
|
||||||
|
(header (cl-mapcar 'centaur-tabs-separator-pattern-to-string (nth 1 patterns)))
|
||||||
|
(footer (cl-mapcar 'centaur-tabs-separator-pattern-to-string (nth 2 patterns)))
|
||||||
|
(second-pattern (centaur-tabs-separator-pattern (cl-mapcar 'centaur-tabs-separator-pattern-to-string (nth 3 patterns))))
|
||||||
|
(center (cl-mapcar 'centaur-tabs-separator-pattern-to-string (nth 4 patterns)))
|
||||||
|
(reserve (+ (length header) (length footer) (length center))))
|
||||||
|
(when pattern
|
||||||
|
(cons `((,pattern-height-sym (max (- ,height-exp ,reserve) 0))
|
||||||
|
(,second-pattern-height-sym (/ ,pattern-height-sym 2))
|
||||||
|
(,pattern-height-sym ,(if second-pattern `(ceiling ,pattern-height-sym 2) `,pattern-height-sym)))
|
||||||
|
(list (when header `(mapconcat 'identity ',header ""))
|
||||||
|
`(mapconcat 'identity
|
||||||
|
(cl-subseq ',pattern 0 ,pattern-height-sym) "")
|
||||||
|
(when center `(mapconcat 'identity ',center ""))
|
||||||
|
(when second-pattern
|
||||||
|
`(mapconcat 'identity
|
||||||
|
(cl-subseq ',second-pattern
|
||||||
|
0 ,second-pattern-height-sym) ""))
|
||||||
|
(when footer `(mapconcat 'identity ',footer "")))))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-pattern-defun (name dir width &rest patterns)
|
||||||
|
"Create a powerline function of NAME in DIR with WIDTH for PATTERNS.
|
||||||
|
|
||||||
|
PATTERNS is of the form (PATTERN HEADER FOOTER SECOND-PATTERN CENTER
|
||||||
|
PATTERN-2X HEADER-2X FOOTER-2X SECOND-PATTERN-2X CENTER-2X).
|
||||||
|
PATTERN is required, all other components are optional.
|
||||||
|
The first 5 components are for the standard resolution image.
|
||||||
|
The remaining ones are for the high resolution image where both
|
||||||
|
width and height are doubled. If PATTERN-2X is nil or not given,
|
||||||
|
then the remaining components are ignored and the standard
|
||||||
|
resolution image with magnification and interpolation will be
|
||||||
|
used in high resolution environments
|
||||||
|
|
||||||
|
All generated functions generate the form:
|
||||||
|
HEADER
|
||||||
|
PATTERN ...
|
||||||
|
CENTER
|
||||||
|
SECOND-PATTERN ...
|
||||||
|
FOOTER
|
||||||
|
|
||||||
|
PATTERN and SECOND-PATTERN repeat infinitely to fill the space needed to
|
||||||
|
generate a full height XPM.
|
||||||
|
|
||||||
|
PATTERN, HEADER, FOOTER, SECOND-PATTERN, CENTER are of the form
|
||||||
|
\((COLOR ...) (COLOR ...) ...).
|
||||||
|
|
||||||
|
COLOR can be one of 0, 1, or 2, where 0 is the source color, 1 is the
|
||||||
|
destination color, and 2 is the interpolated color between 0 and 1."
|
||||||
|
(when (eq dir 'right)
|
||||||
|
(setq patterns (cl-mapcar 'centaur-tabs-separator-reverse-pattern patterns)))
|
||||||
|
(let ((bindings-body (centaur-tabs-separator-pattern-bindings-body patterns
|
||||||
|
'height
|
||||||
|
'pattern-height
|
||||||
|
'second-pattern-height))
|
||||||
|
(bindings-body-2x (centaur-tabs-separator-pattern-bindings-body (nthcdr 5 patterns)
|
||||||
|
'(* height 2)
|
||||||
|
'pattern-height-2x
|
||||||
|
'second-pattern-height-2x)))
|
||||||
|
(centaur-tabs-separator-wrap-defun name dir width
|
||||||
|
(append (car bindings-body) (car bindings-body-2x))
|
||||||
|
(cdr bindings-body) (cdr bindings-body-2x))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-background-color (face)
|
||||||
|
"Set the separator background color using FACE."
|
||||||
|
(face-attribute face
|
||||||
|
(if (face-attribute face :inverse-video nil 'default)
|
||||||
|
:foreground
|
||||||
|
:background)
|
||||||
|
nil
|
||||||
|
'default))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-wrap-defun (name dir width let-vars body &optional body-2x)
|
||||||
|
"Generate a powerline function of name NAME in dir DIR.
|
||||||
|
This is made with WIDTH using LET-VARS and BODY.
|
||||||
|
BODY-2X is an optional argument."
|
||||||
|
(let* ((src-face (if (eq dir 'left) 'face1 'face2))
|
||||||
|
(dst-face (if (eq dir 'left) 'face2 'face1)))
|
||||||
|
`(defun ,(intern (format "powerline-%s-%s" name (symbol-name dir)))
|
||||||
|
(face1 face2 &optional height)
|
||||||
|
(when window-system
|
||||||
|
(unless height (setq height centaur-tabs-height))
|
||||||
|
(let* ,(append `((color1 (when ,src-face
|
||||||
|
(centaur-tabs-separator-hex-color (centaur-tabs-separator-background-color ,src-face))))
|
||||||
|
(color2 (when ,dst-face
|
||||||
|
(centaur-tabs-separator-hex-color (centaur-tabs-separator-background-color ,dst-face))))
|
||||||
|
(colori (when (and color1 color2) (centaur-tabs-separator-interpolate color1 color2)))
|
||||||
|
(color1 (or color1 "None"))
|
||||||
|
(color2 (or color2 "None"))
|
||||||
|
(colori (or colori "None")))
|
||||||
|
let-vars)
|
||||||
|
(apply #'create-image
|
||||||
|
,(append `(concat (format "/* XPM */ static char * %s_%s[] = { \"%s %s 3 1\", \"0 c %s\", \"1 c %s\", \"2 c %s\","
|
||||||
|
,(replace-regexp-in-string "-" "_" name)
|
||||||
|
(symbol-name ',dir)
|
||||||
|
,width
|
||||||
|
height
|
||||||
|
color1
|
||||||
|
color2
|
||||||
|
colori))
|
||||||
|
body
|
||||||
|
'("};"))
|
||||||
|
'xpm t
|
||||||
|
:ascent 'center
|
||||||
|
:face (when (and face1 face2)
|
||||||
|
,dst-face)
|
||||||
|
,(and body-2x
|
||||||
|
`(and (featurep 'mac)
|
||||||
|
(list :data-2x
|
||||||
|
,(append `(concat (format "/* XPM */ static char * %s_%s_2x[] = { \"%s %s 3 1\", \"0 c %s\", \"1 c %s\", \"2 c %s\","
|
||||||
|
,(replace-regexp-in-string "-" "_" name)
|
||||||
|
(symbol-name ',dir)
|
||||||
|
(* ,width 2)
|
||||||
|
(* height 2)
|
||||||
|
color1
|
||||||
|
color2
|
||||||
|
colori))
|
||||||
|
body-2x
|
||||||
|
'("};")))))))))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-alternate (dir)
|
||||||
|
"Generate an alternating pattern XPM function for DIR."
|
||||||
|
(centaur-tabs-separator-pattern-defun "alternate" dir 4
|
||||||
|
'((2 2 1 1)
|
||||||
|
(0 0 2 2))
|
||||||
|
nil nil nil nil
|
||||||
|
;; 2x
|
||||||
|
'((2 2 2 2 1 1 1 1)
|
||||||
|
(2 2 2 2 1 1 1 1)
|
||||||
|
(0 0 0 0 2 2 2 2)
|
||||||
|
(0 0 0 0 2 2 2 2))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-bar (dir)
|
||||||
|
"Generate a bar XPM function for DIR."
|
||||||
|
(centaur-tabs-separator-pattern-defun "bar" dir 2
|
||||||
|
'((2 2))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-box (dir)
|
||||||
|
"Generate a box XPM function for DIR."
|
||||||
|
(centaur-tabs-separator-pattern-defun "box" dir 2
|
||||||
|
'((0 0)
|
||||||
|
(0 0)
|
||||||
|
(1 1)
|
||||||
|
(1 1))
|
||||||
|
nil nil nil nil
|
||||||
|
;; 2x
|
||||||
|
'((0 0 0 0)
|
||||||
|
(0 0 0 0)
|
||||||
|
(0 0 0 0)
|
||||||
|
(0 0 0 0)
|
||||||
|
(1 1 1 1)
|
||||||
|
(1 1 1 1)
|
||||||
|
(1 1 1 1)
|
||||||
|
(1 1 1 1))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-chamfer (dir)
|
||||||
|
"Generate a chamfer XPM function for DIR."
|
||||||
|
(centaur-tabs-separator-pattern-defun "chamfer" dir 3
|
||||||
|
'((0 0 0))
|
||||||
|
'((1 1 1)
|
||||||
|
(0 1 1)
|
||||||
|
(0 0 1))
|
||||||
|
nil nil nil
|
||||||
|
;; 2x
|
||||||
|
'((0 0 0 0 0 0))
|
||||||
|
'((1 1 1 1 1 1)
|
||||||
|
(0 1 1 1 1 1)
|
||||||
|
(0 0 1 1 1 1)
|
||||||
|
(0 0 0 1 1 1)
|
||||||
|
(0 0 0 0 1 1)
|
||||||
|
(0 0 0 0 0 1))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-rounded (dir)
|
||||||
|
"Generate a rounded XPM function for DIR."
|
||||||
|
(centaur-tabs-separator-pattern-defun "rounded" dir 6
|
||||||
|
'((0 0 0 0 0 0))
|
||||||
|
'((2 1 1 1 1 1)
|
||||||
|
(0 0 2 1 1 1)
|
||||||
|
(0 0 0 0 1 1)
|
||||||
|
(0 0 0 0 2 1)
|
||||||
|
(0 0 0 0 0 1)
|
||||||
|
(0 0 0 0 0 2))
|
||||||
|
nil nil nil
|
||||||
|
;; 2x
|
||||||
|
'((0 0 0 0 0 0 0 0 0 0 0 0))
|
||||||
|
'((1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 2 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 2 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 2 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 1))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-slant (dir)
|
||||||
|
"Generate a slant XPM function for DIR."
|
||||||
|
(let* ((row-modifier (if (eq dir 'left) 'identity 'reverse)))
|
||||||
|
(centaur-tabs-separator-wrap-defun "slant" dir 'width
|
||||||
|
'((width (1- (ceiling height 2))))
|
||||||
|
`((cl-loop for i from 0 to (1- height)
|
||||||
|
concat (centaur-tabs-separator-pattern-to-string (,row-modifier (centaur-tabs-separator-row-pattern (/ i 2) width)))))
|
||||||
|
`((cl-loop for i from 0 to (1- (* height 2))
|
||||||
|
concat (centaur-tabs-separator-pattern-to-string (,row-modifier (centaur-tabs-separator-row-pattern (/ i 2) (* width 2)))))))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-wave (dir)
|
||||||
|
"Generate a wave XPM function for DIR."
|
||||||
|
(centaur-tabs-separator-pattern-defun "wave" dir 11
|
||||||
|
'((0 0 0 0 0 0 1 1 1 1 1))
|
||||||
|
'((2 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 2 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 2 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 2 1 1 1 1 1))
|
||||||
|
'((0 0 0 0 0 0 2 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 2 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 2 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 2))
|
||||||
|
nil nil
|
||||||
|
;; 2x
|
||||||
|
'((0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1))
|
||||||
|
'((1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1))
|
||||||
|
'((0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1)
|
||||||
|
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-zigzag (dir)
|
||||||
|
"Generate a zigzag pattern XPM function for DIR."
|
||||||
|
(centaur-tabs-separator-pattern-defun "zigzag" dir 3
|
||||||
|
'((1 1 1)
|
||||||
|
(0 1 1)
|
||||||
|
(0 0 1)
|
||||||
|
(0 0 0)
|
||||||
|
(0 0 1)
|
||||||
|
(0 1 1))
|
||||||
|
nil nil nil nil
|
||||||
|
;; 2x
|
||||||
|
'((1 1 1 1 1 1)
|
||||||
|
(0 1 1 1 1 1)
|
||||||
|
(0 0 1 1 1 1)
|
||||||
|
(0 0 0 1 1 1)
|
||||||
|
(0 0 0 0 1 1)
|
||||||
|
(0 0 0 0 0 1)
|
||||||
|
(0 0 0 0 0 0)
|
||||||
|
(0 0 0 0 0 1)
|
||||||
|
(0 0 0 0 1 1)
|
||||||
|
(0 0 0 1 1 1)
|
||||||
|
(0 0 1 1 1 1)
|
||||||
|
(0 1 1 1 1 1))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-memoize (func)
|
||||||
|
"Memoize FUNC.
|
||||||
|
If argument is a symbol then install the memoized function over
|
||||||
|
the original function. Use frame-local memoization."
|
||||||
|
(cl-typecase func
|
||||||
|
(symbol (fset func (centaur-tabs-separator-memoize-wrap-frame-local (symbol-function func))) func)
|
||||||
|
(function (centaur-tabs-separator-memoize-wrap-frame-local func))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-memoize-wrap-frame-local (func)
|
||||||
|
"Return the memoized version of FUNC.
|
||||||
|
The memoization cache is frame-local."
|
||||||
|
(let ((funcid (cl-gensym)))
|
||||||
|
`(lambda (&rest args)
|
||||||
|
,(concat (documentation func) (format "\n(memoized function %s)" funcid))
|
||||||
|
(let* ((cache (centaur-tabs-separator-create-or-get-cache))
|
||||||
|
(key (cons ',funcid args))
|
||||||
|
(val (gethash key cache)))
|
||||||
|
(if val
|
||||||
|
val
|
||||||
|
(puthash key (apply ,func args) cache))))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-create-or-get-cache ()
|
||||||
|
"Return a frame-local hash table that acts as a memoization cache.
|
||||||
|
The cache is for the powerline.
|
||||||
|
Create one if the frame doesn't have one yet."
|
||||||
|
(let ((table (frame-parameter nil 'powerline-cache)))
|
||||||
|
(if (hash-table-p table) table (centaur-tabs-separator-reset-cache))))
|
||||||
|
|
||||||
|
(defun centaur-tabs-separator-reset-cache ()
|
||||||
|
"Reset and return the frame-local hash table used for a memoization cache."
|
||||||
|
(let ((table (make-hash-table :test 'equal)))
|
||||||
|
;; Store it as a frame-local variable
|
||||||
|
(modify-frame-parameters nil `((powerline-cache . ,table)))
|
||||||
|
table))
|
||||||
|
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-alternate 'left))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-alternate 'right))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-bar 'left))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-bar 'right))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-box 'left))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-box 'right))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-chamfer 'left))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-chamfer 'right))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-rounded 'left))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-rounded 'right))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-slant 'left))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-slant 'right))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-wave 'left))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-wave 'right))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-zigzag 'left))
|
||||||
|
(centaur-tabs-separator-memoize (centaur-tabs-separator-zigzag 'right))
|
||||||
|
|
||||||
|
(defun centaur-tabs-select-separator-style (tab-style)
|
||||||
|
"Set the separator style to TAB-STYLE."
|
||||||
|
(setq centaur-tabs-style-left (funcall (intern (format "powerline-%s-right" tab-style)) 'centaur-tabs-default nil centaur-tabs-height))
|
||||||
|
(setq centaur-tabs-style-right (funcall (intern (format "powerline-%s-left" tab-style)) nil 'centaur-tabs-default centaur-tabs-height)))
|
||||||
|
|
||||||
|
(provide 'centaur-tabs-elements)
|
||||||
|
|
||||||
|
;;; centaur-tabs-elements.el ends here
|
File diff suppressed because it is too large
Load diff
|
@ -1,10 +1,10 @@
|
||||||
;;; centaur-tabs-interactive.el --- centaur-tabs interactive functions and plugins support lexical-binding: t; -*-
|
;;; centaur-tabs-interactive.el --- centaur-tabs interactive functions and plugins support lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2019-2024 Emmanuel Bustos
|
;; Copyright (C) 2019-2020 Emmanuel Bustos
|
||||||
;; Copyright (C) 2024 Jen-Chieh Shen
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
;; This file is not part of GNU Emacs.
|
||||||
|
|
||||||
|
;;
|
||||||
;; This program is free software; you can redistribute it and/or
|
;; This program is free software; you can redistribute it and/or
|
||||||
;; modify it under the terms of the GNU General Public License as
|
;; modify it under the terms of the GNU General Public License as
|
||||||
;; published by the Free Software Foundation; either version 2, or
|
;; published by the Free Software Foundation; either version 2, or
|
||||||
|
@ -19,73 +19,34 @@
|
||||||
;; along with this program; see the file COPYING. If not, write to
|
;; along with this program; see the file COPYING. If not, write to
|
||||||
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
||||||
;; Floor, Boston, MA 02110-1301, USA.
|
;; Floor, Boston, MA 02110-1301, USA.
|
||||||
|
;;
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;
|
|
||||||
;; This file contains centaur-tabs interactive functions and plugins support
|
;; This file contains centaur-tabs interactive functions and plugins support
|
||||||
;;
|
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
;;; Requires
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'centaur-tabs-elements)
|
(require 'centaur-tabs-elements)
|
||||||
|
(require 'centaur-tabs-functions)
|
||||||
;; Compiler pacifier
|
|
||||||
(declare-function ivy-read "ext:ivy.el" t t)
|
|
||||||
(declare-function helm-build-sync-source "ext:helm-source.el" t t)
|
|
||||||
(defvar helm-source-centaur-tabs-group)
|
|
||||||
(declare-function projectile-project-root "ext:projectile.el" t t)
|
|
||||||
(declare-function projectile-project-name "ext:projectile.el" t t)
|
|
||||||
|
|
||||||
(declare-function centaur-tabs-do-select "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-tab-from-event "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-tab-value "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-tabset "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-buffer-show-groups "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-buffer-close-tab "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-view "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-extensions "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-selected-tab "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-display-update "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-set-template "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-buffer-select-tab "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-tabs "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-tab-tabset "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-tabsets-tabset "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-current-tabset "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-completing-read "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-groups "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-forward-group "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-backward-group "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-forward-tab "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-backward-tab "centaur-tabs-functions.el")
|
|
||||||
|
|
||||||
(defvar centaur-tabs-cycle-scope)
|
|
||||||
(defvar centaur-tabs-current-tabset)
|
|
||||||
(defvar centaur-tabs-last-focused-buffer-group)
|
|
||||||
(defvar centaur-tabs-buffer-list-function)
|
|
||||||
(defvar centaur-tabs-buffer-groups-function)
|
|
||||||
(defvar centaur-tabs--buffer-show-groups)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;; Interactive functions ;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;; Interactive functions ;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defun centaur-tabs-switch-group (&optional groupname)
|
(defun centaur-tabs-switch-group (&optional groupname)
|
||||||
"Switch tab groups using ido. GROUPNAME can optionaly be provided."
|
"Switch tab groups using ido. GROUPNAME can optionaly be provided."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((tab-buffer-list (mapcar
|
(let* ((tab-buffer-list (cl-mapcar
|
||||||
#'(lambda (b)
|
#'(lambda (b)
|
||||||
(with-current-buffer b
|
(with-current-buffer b
|
||||||
(list (current-buffer)
|
(list (current-buffer)
|
||||||
(buffer-name)
|
(buffer-name)
|
||||||
(funcall centaur-tabs-buffer-groups-function) )))
|
(funcall centaur-tabs-buffer-groups-function) )))
|
||||||
(funcall centaur-tabs-buffer-list-function)))
|
(funcall centaur-tabs-buffer-list-function)))
|
||||||
(groups (centaur-tabs-get-groups))
|
(groups (centaur-tabs-get-groups))
|
||||||
(group-name (or groupname (centaur-tabs-completing-read "Groups: " groups))) )
|
(group-name (or groupname (centaur-tabs-completing-read "Groups: " groups))) )
|
||||||
(catch 'done
|
(catch 'done
|
||||||
(mapc #'(lambda (group)
|
(mapc
|
||||||
(when (equal group-name (car (car (cdr (cdr group)))))
|
#'(lambda (group)
|
||||||
(throw 'done (switch-to-buffer (car (cdr group))))))
|
(when (equal group-name (car (car (cdr (cdr group)))))
|
||||||
tab-buffer-list) )))
|
(throw 'done (switch-to-buffer (car (cdr group))))))
|
||||||
|
tab-buffer-list) )))
|
||||||
|
|
||||||
(defun centaur-tabs-select-end-tab ()
|
(defun centaur-tabs-select-end-tab ()
|
||||||
"Select end tab of current tabset."
|
"Select end tab of current tabset."
|
||||||
|
@ -98,21 +59,20 @@ If BACKWARD is non-nil, move backward, otherwise move forward.
|
||||||
TYPE is default option."
|
TYPE is default option."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((tabset (centaur-tabs-current-tabset t))
|
(let* ((tabset (centaur-tabs-current-tabset t))
|
||||||
(ttabset (centaur-tabs-get-tabsets-tabset))
|
(ttabset (centaur-tabs-get-tabsets-tabset))
|
||||||
(_cycle (if (and (eq centaur-tabs-cycle-scope 'groups)
|
(_cycle (if (and (eq centaur-tabs-cycle-scope 'groups)
|
||||||
(not (cdr (centaur-tabs-tabs ttabset))))
|
(not (cdr (centaur-tabs-tabs ttabset))))
|
||||||
'tabs
|
'tabs
|
||||||
centaur-tabs-cycle-scope))
|
centaur-tabs-cycle-scope))
|
||||||
_selected tab)
|
_selected tab)
|
||||||
(when tabset
|
(when tabset
|
||||||
(setq tabset (centaur-tabs-tabs tabset)
|
(setq tabset (centaur-tabs-tabs tabset)
|
||||||
tab (car (if backward (last tabset) tabset)))
|
tab (car (if backward (last tabset) tabset)))
|
||||||
(centaur-tabs-buffer-select-tab tab))))
|
(centaur-tabs-buffer-select-tab tab))))
|
||||||
|
|
||||||
(defun centaur-tabs-backward-tab-other-window (&optional reversed)
|
(defun centaur-tabs-backward-tab-other-window (&optional reversed)
|
||||||
"Move to left tab in other window.
|
"Move to left tab in other window.
|
||||||
Optional argument REVERSED default is move backward, if reversed is non-nil
|
Optional argument REVERSED default is move backward, if reversed is non-nil move forward."
|
||||||
move forward."
|
|
||||||
(interactive)
|
(interactive)
|
||||||
(other-window 1)
|
(other-window 1)
|
||||||
(if reversed
|
(if reversed
|
||||||
|
@ -129,21 +89,21 @@ move forward."
|
||||||
"Move current tab one place right, unless it's already the rightmost."
|
"Move current tab one place right, unless it's already the rightmost."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((bufset (centaur-tabs-current-tabset t))
|
(let* ((bufset (centaur-tabs-current-tabset t))
|
||||||
(old-bufs (centaur-tabs-tabs bufset))
|
(old-bufs (centaur-tabs-tabs bufset))
|
||||||
(new-bufs (list))
|
(new-bufs (list))
|
||||||
the-buffer)
|
the-buffer)
|
||||||
(while (and
|
(while (and
|
||||||
old-bufs
|
old-bufs
|
||||||
(not (string= (buffer-name) (format "%s" (car (car old-bufs))))))
|
(not (string= (buffer-name) (format "%s" (car (car old-bufs))))))
|
||||||
(push (car old-bufs) new-bufs)
|
(push (car old-bufs) new-bufs)
|
||||||
(setq old-bufs (cdr old-bufs)))
|
(setq old-bufs (cdr old-bufs)))
|
||||||
(if old-bufs ; if this is false, then the current tab's buffer name is mysteriously missing
|
(if old-bufs ; if this is false, then the current tab's buffer name is mysteriously missing
|
||||||
(progn
|
(progn
|
||||||
(setq the-buffer (car old-bufs))
|
(setq the-buffer (car old-bufs))
|
||||||
(setq old-bufs (cdr old-bufs))
|
(setq old-bufs (cdr old-bufs))
|
||||||
(if old-bufs ; if this is false, then the current tab is the rightmost
|
(if old-bufs ; if this is false, then the current tab is the rightmost
|
||||||
(push (car old-bufs) new-bufs))
|
(push (car old-bufs) new-bufs))
|
||||||
(push the-buffer new-bufs)) ; this is the tab that was to be moved
|
(push the-buffer new-bufs)) ; this is the tab that was to be moved
|
||||||
(error "Error: current buffer's name was not found in Centaur-Tabs's buffer list"))
|
(error "Error: current buffer's name was not found in Centaur-Tabs's buffer list"))
|
||||||
(setq new-bufs (reverse new-bufs))
|
(setq new-bufs (reverse new-bufs))
|
||||||
(setq new-bufs (append new-bufs (cdr old-bufs)))
|
(setq new-bufs (append new-bufs (cdr old-bufs)))
|
||||||
|
@ -155,27 +115,27 @@ move forward."
|
||||||
"Move current tab one place left, unless it's already the leftmost."
|
"Move current tab one place left, unless it's already the leftmost."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((bufset (centaur-tabs-current-tabset t))
|
(let* ((bufset (centaur-tabs-current-tabset t))
|
||||||
(old-bufs (centaur-tabs-tabs bufset))
|
(old-bufs (centaur-tabs-tabs bufset))
|
||||||
(first-buf (car old-bufs))
|
(first-buf (car old-bufs))
|
||||||
(new-bufs (list))
|
(new-bufs (list))
|
||||||
not-yet-this-buf)
|
not-yet-this-buf)
|
||||||
(if (string= (buffer-name) (format "%s" (car first-buf)))
|
(if (string= (buffer-name) (format "%s" (car first-buf)))
|
||||||
old-bufs ; the current tab is the leftmost
|
old-bufs ; the current tab is the leftmost
|
||||||
(setq not-yet-this-buf first-buf)
|
(setq not-yet-this-buf first-buf)
|
||||||
(setq old-bufs (cdr old-bufs))
|
(setq old-bufs (cdr old-bufs))
|
||||||
(while (and
|
(while (and
|
||||||
old-bufs
|
old-bufs
|
||||||
(not (string= (buffer-name) (format "%s" (car (car old-bufs))))))
|
(not (string= (buffer-name) (format "%s" (car (car old-bufs))))))
|
||||||
(push not-yet-this-buf new-bufs)
|
(push not-yet-this-buf new-bufs)
|
||||||
(setq not-yet-this-buf (car old-bufs))
|
(setq not-yet-this-buf (car old-bufs))
|
||||||
(setq old-bufs (cdr old-bufs)))
|
(setq old-bufs (cdr old-bufs)))
|
||||||
(if old-bufs ; if this is false, then the current tab's buffer name is mysteriously missing
|
(if old-bufs ; if this is false, then the current tab's buffer name is mysteriously missing
|
||||||
(progn
|
(progn
|
||||||
(push (car old-bufs) new-bufs) ; this is the tab that was to be moved
|
(push (car old-bufs) new-bufs) ; this is the tab that was to be moved
|
||||||
(push not-yet-this-buf new-bufs)
|
(push not-yet-this-buf new-bufs)
|
||||||
(setq new-bufs (reverse new-bufs))
|
(setq new-bufs (reverse new-bufs))
|
||||||
(setq new-bufs (append new-bufs (cdr old-bufs))))
|
(setq new-bufs (append new-bufs (cdr old-bufs))))
|
||||||
(error "Error: current buffer's name was not found in Centaur-Tabs's buffer list"))
|
(error "Error: current buffer's name was not found in Centaur-Tabs's buffer list"))
|
||||||
(set bufset new-bufs)
|
(set bufset new-bufs)
|
||||||
(centaur-tabs-set-template bufset nil)
|
(centaur-tabs-set-template bufset nil)
|
||||||
(centaur-tabs-display-update))))
|
(centaur-tabs-display-update))))
|
||||||
|
@ -184,11 +144,12 @@ move forward."
|
||||||
"If buffer match MATCH-RULE, kill it."
|
"If buffer match MATCH-RULE, kill it."
|
||||||
`(save-excursion
|
`(save-excursion
|
||||||
(mapc #'(lambda (buffer)
|
(mapc #'(lambda (buffer)
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
(when (string-equal current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
(when (string-equal current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
||||||
(when (funcall ,match-rule buffer)
|
(when (funcall ,match-rule buffer)
|
||||||
(kill-buffer buffer)))))
|
(kill-buffer buffer))
|
||||||
(buffer-list))))
|
)))
|
||||||
|
(buffer-list))))
|
||||||
|
|
||||||
(defun centaur-tabs-kill-all-buffers-in-current-group ()
|
(defun centaur-tabs-kill-all-buffers-in-current-group ()
|
||||||
"Kill all buffers in current group."
|
"Kill all buffers in current group."
|
||||||
|
@ -198,59 +159,67 @@ move forward."
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
(centaur-tabs-kill-buffer-match-rule
|
||||||
(lambda (_buffer) t))
|
(lambda (_buffer) t))
|
||||||
;; Switch to next group.
|
;; Switch to next group.
|
||||||
(centaur-tabs-forward-group)))
|
(centaur-tabs-forward-group)
|
||||||
|
))
|
||||||
|
|
||||||
(defun centaur-tabs-kill-other-buffers-in-current-group ()
|
(defun centaur-tabs-kill-other-buffers-in-current-group ()
|
||||||
"Kill all buffers except current buffer in current group."
|
"Kill all buffers except current buffer in current group."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
||||||
(currentbuffer (current-buffer)))
|
(currentbuffer (current-buffer)))
|
||||||
;; Kill all buffers in current group.
|
;; Kill all buffers in current group.
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
(centaur-tabs-kill-buffer-match-rule
|
||||||
(lambda (buffer) (not (equal buffer currentbuffer))))))
|
(lambda (buffer) (not (equal buffer currentbuffer))))
|
||||||
|
))
|
||||||
|
|
||||||
(defun centaur-tabs-kill-unmodified-buffers-in-current-group ()
|
(defun centaur-tabs-kill-unmodified-buffers-in-current-group ()
|
||||||
"Kill all unmodified buffer in current group."
|
"Kill all unmodified buffer in current group."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
||||||
(currentbuffer (current-buffer)))
|
(currentbuffer (current-buffer)))
|
||||||
;; Kill all buffers in current group.
|
;; Kill all buffers in current group.
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
(centaur-tabs-kill-buffer-match-rule
|
||||||
(lambda (buffer) (not (buffer-modified-p buffer))))))
|
(lambda (buffer) (not (buffer-modified-p buffer))))
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
(defun centaur-tabs-kill-match-buffers-in-current-group ()
|
(defun centaur-tabs-kill-match-buffers-in-current-group ()
|
||||||
"Kill all buffers match extension in current group."
|
"Kill all buffers match extension in current group."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
||||||
(extension-names (centaur-tabs-get-extensions))
|
(extension-names (centaur-tabs-get-extensions))
|
||||||
match-extension)
|
match-extension)
|
||||||
;; Read extension need to kill.
|
;; Read extension need to kill.
|
||||||
(setq match-extension (centaur-tabs-completing-read "Kill buffers suffix with: " extension-names))
|
(setq match-extension (centaur-tabs-completing-read "Kill buffers suffix with: " extension-names))
|
||||||
;; Kill all buffers match extension in current group.
|
;; Kill all buffers match extension in current group.
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
(centaur-tabs-kill-buffer-match-rule
|
||||||
(lambda (buffer)
|
(lambda (buffer)
|
||||||
(let ((filename (buffer-file-name buffer)))
|
(let ((filename (buffer-file-name buffer)))
|
||||||
(and filename (string-equal (file-name-extension filename) match-extension)))))
|
(and filename (string-equal (file-name-extension filename) match-extension))
|
||||||
|
)))
|
||||||
;; Switch to next group if last file killed.
|
;; Switch to next group if last file killed.
|
||||||
(when (equal (length extension-names) 1)
|
(when (equal (length extension-names) 1)
|
||||||
(centaur-tabs-forward-group))))
|
(centaur-tabs-forward-group))
|
||||||
|
))
|
||||||
|
|
||||||
(defun centaur-tabs-keep-match-buffers-in-current-group ()
|
(defun centaur-tabs-keep-match-buffers-in-current-group ()
|
||||||
"Keep all buffers match extension in current group."
|
"Keep all buffers match extension in current group."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
||||||
(extension-names (centaur-tabs-get-extensions))
|
(extension-names (centaur-tabs-get-extensions))
|
||||||
match-extension)
|
match-extension)
|
||||||
;; Read extension need to kill.
|
;; Read extension need to kill.
|
||||||
(setq match-extension (centaur-tabs-completing-read "Just keep buffers suffix with: " extension-names))
|
(setq match-extension (centaur-tabs-completing-read "Just keep buffers suffix with: " extension-names))
|
||||||
;; Kill all buffers match extension in current group.
|
;; Kill all buffers match extension in current group.
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
(centaur-tabs-kill-buffer-match-rule
|
||||||
(lambda (buffer)
|
(lambda (buffer)
|
||||||
(let ((filename (buffer-file-name buffer)))
|
(let ((filename (buffer-file-name buffer)))
|
||||||
(and filename (not (string-equal (file-name-extension filename) match-extension))))))
|
(and filename (not (string-equal (file-name-extension filename) match-extension)))
|
||||||
|
)))
|
||||||
;; Switch to next group if last file killed.
|
;; Switch to next group if last file killed.
|
||||||
(when (equal (length extension-names) 1)
|
(when (equal (length extension-names) 1)
|
||||||
(centaur-tabs-forward-group))))
|
(centaur-tabs-forward-group))
|
||||||
|
))
|
||||||
|
|
||||||
(defun centaur-tabs-select-visible-nth-tab (tab-index)
|
(defun centaur-tabs-select-visible-nth-tab (tab-index)
|
||||||
"Select visible tab with TAB-INDEX'.
|
"Select visible tab with TAB-INDEX'.
|
||||||
|
@ -263,9 +232,9 @@ If `tab-index' is 0, select last tab."
|
||||||
(switch-to-buffer
|
(switch-to-buffer
|
||||||
(car
|
(car
|
||||||
(if (or (equal tab-index 0)
|
(if (or (equal tab-index 0)
|
||||||
(> tab-index (length visible-tabs)))
|
(> tab-index (length visible-tabs)))
|
||||||
(car (last visible-tabs))
|
(car (last visible-tabs))
|
||||||
(nth (- tab-index 1) visible-tabs))))))
|
(nth (- tab-index 1) visible-tabs))))))
|
||||||
|
|
||||||
(defun centaur-tabs-select-visible-tab ()
|
(defun centaur-tabs-select-visible-tab ()
|
||||||
"Bind this function with number keystroke, such as s-1, s-2, s-3 ... etc.
|
"Bind this function with number keystroke, such as s-1, s-2, s-3 ... etc.
|
||||||
|
@ -277,15 +246,15 @@ Note that this function switches to the visible range,
|
||||||
not the actual logical index position of the current group."
|
not the actual logical index position of the current group."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((event last-command-event)
|
(let* ((event last-command-event)
|
||||||
(key (make-vector 1 event))
|
(key (make-vector 1 event))
|
||||||
(key-desc (key-description key)))
|
(key-desc (key-description key)))
|
||||||
(centaur-tabs-select-visible-nth-tab
|
(centaur-tabs-select-visible-nth-tab
|
||||||
(string-to-number (car (last (split-string key-desc "-")))))))
|
(string-to-number (car (last (split-string key-desc "-")))))))
|
||||||
|
|
||||||
;; ace-jump style tab switching
|
;; ace-jump style tab switching
|
||||||
|
|
||||||
(defvar centaur-tabs-ace-jump-active nil
|
(defvar centaur-tabs-ace-jump-active nil
|
||||||
"Set to t if `centaur-tabs-ace-jump' is invoked.")
|
"t if centaur-tabs-ace-jump is invoked.")
|
||||||
|
|
||||||
(defvar centaur-tabs-dim-overlay nil
|
(defvar centaur-tabs-dim-overlay nil
|
||||||
"Holds the overlay for dimming buffer when invoking centaur-tabs-ace-jump.")
|
"Holds the overlay for dimming buffer when invoking centaur-tabs-ace-jump.")
|
||||||
|
@ -296,91 +265,91 @@ not the actual logical index position of the current group."
|
||||||
(when centaur-tabs-dim-overlay
|
(when centaur-tabs-dim-overlay
|
||||||
(delete-overlay centaur-tabs-dim-overlay))
|
(delete-overlay centaur-tabs-dim-overlay))
|
||||||
(setq centaur-tabs-dim-overlay
|
(setq centaur-tabs-dim-overlay
|
||||||
(let ((ol (make-overlay (window-start) (window-end))))
|
(let ((ol (make-overlay (window-start) (window-end))))
|
||||||
(overlay-put ol 'face 'centaur-tabs-dim-buffer-face)
|
(overlay-put ol 'face 'centaur-tabs-dim-buffer-face)
|
||||||
ol))))
|
ol))))
|
||||||
|
|
||||||
(defun centaur-tabs-swap-tab (tab)
|
(defun centaur-tabs-swap-tab (tab)
|
||||||
"Swap the position of current tab with TAB.
|
"Swap the position of current tab with TAB.
|
||||||
TAB has to be in the same group as the current tab."
|
TAB has to be in the same group as the current tab."
|
||||||
(if (eq (centaur-tabs-tab-tabset tab) (centaur-tabs-current-tabset t))
|
(if (eq (centaur-tabs-tab-tabset tab) (centaur-tabs-current-tabset t))
|
||||||
(let* ((group (centaur-tabs-current-tabset t))
|
(let* ((group (centaur-tabs-current-tabset t))
|
||||||
(tabs (cl-copy-list (centaur-tabs-tabs group)))
|
(tabs (cl-copy-list (centaur-tabs-tabs group)))
|
||||||
(current (centaur-tabs-selected-tab group))
|
(current (centaur-tabs-selected-tab group))
|
||||||
(current-index (cl-position current tabs))
|
(current-index (cl-position current tabs))
|
||||||
(target-index (cl-position tab tabs)))
|
(target-index (cl-position tab tabs)))
|
||||||
(if (eq tab current)
|
(if (eq tab current)
|
||||||
(message "Can't swap with current tab itself.")
|
(message "Can't swap with current tab itself.")
|
||||||
(setcar (nthcdr current-index tabs) tab)
|
(setcar (nthcdr current-index tabs) tab)
|
||||||
(setcar (nthcdr target-index tabs) current)
|
(setcar (nthcdr target-index tabs) current)
|
||||||
(set group tabs)
|
(set group tabs)
|
||||||
(centaur-tabs-set-template (centaur-tabs-current-tabset t) nil)
|
(centaur-tabs-set-template (centaur-tabs-current-tabset t) nil)
|
||||||
(centaur-tabs-display-update)))
|
(centaur-tabs-display-update)))
|
||||||
(message "Error: %s is not in the same group as the current tab." tab)))
|
(message "Error: %s is not in the same group as the current tab." tab)))
|
||||||
|
|
||||||
(defun centaur-tabs-ace-action (action)
|
(defun centaur-tabs-ace-action (action)
|
||||||
"Preform ACTION on a visible tab. Ace-jump style.
|
"Preform ACTION on a visible tab. Ace-jump style.
|
||||||
ACTION has to be one of value in `centaur-tabs-ace-dispatch-alist'"
|
ACTION has to be one of value in `centuar-tabs-ace-dispatch-alist'"
|
||||||
(when (centaur-tabs-current-tabset t)
|
(when (centaur-tabs-current-tabset t)
|
||||||
(when centaur-tabs-ace-jump-dim-buffer
|
(when centaur-tabs-ace-jump-dim-buffer
|
||||||
(centaur-tabs--dim-window))
|
(centaur-tabs--dim-window))
|
||||||
(cond ((eq action 'jump-to-tab)
|
(cond ((eq action 'jump-to-tab)
|
||||||
(message "Jump to tab: "))
|
(message "Jump to tab: "))
|
||||||
((eq action 'close-tab)
|
((eq action 'close-tab)
|
||||||
(message "Close tab: "))
|
(message "Close tab: "))
|
||||||
((eq action 'swap-tab)
|
((eq action 'swap-tab)
|
||||||
(message "Swap current tab with: ")))
|
(message "Swap current tab with: ")))
|
||||||
|
|
||||||
(let ((centaur-tabs-ace-jump-active t))
|
(let ((centaur-tabs-ace-jump-active t))
|
||||||
(catch 'done
|
(catch 'done
|
||||||
(while t
|
(while t
|
||||||
(centaur-tabs-set-template (centaur-tabs-current-tabset t) nil)
|
(centaur-tabs-set-template (centaur-tabs-current-tabset t) nil)
|
||||||
(centaur-tabs-display-update)
|
(centaur-tabs-display-update)
|
||||||
(let ((char (read-key)) (action-cache))
|
(let ((char (read-key)) (action-cache))
|
||||||
(cond
|
(cond
|
||||||
;; tab keys
|
;; tab keys
|
||||||
((memq char centaur-tabs-ace-jump-keys)
|
((memq char centaur-tabs-ace-jump-keys)
|
||||||
(let ((sel (nth (cl-position char centaur-tabs-ace-jump-keys) (centaur-tabs-view (centaur-tabs-current-tabset t)))))
|
(let ((sel (nth (cl-position char centaur-tabs-ace-jump-keys) (centaur-tabs-view (centaur-tabs-current-tabset t)))))
|
||||||
(cond ((eq sel nil)
|
(cond ((eq sel nil)
|
||||||
(message "Tab %s does not exist" (key-description (vector char))))
|
(message "Tab %s does not exist" (key-description (vector char))))
|
||||||
((eq action 'jump-to-tab)
|
((eq action 'jump-to-tab)
|
||||||
(centaur-tabs-buffer-select-tab sel))
|
(centaur-tabs-buffer-select-tab sel))
|
||||||
((eq action 'close-tab)
|
((eq action 'close-tab)
|
||||||
(centaur-tabs-buffer-close-tab sel))
|
(centaur-tabs-buffer-close-tab sel))
|
||||||
((eq action 'swap-tab)
|
((eq action 'swap-tab)
|
||||||
(centaur-tabs-swap-tab sel))))
|
(centaur-tabs-swap-tab sel))))
|
||||||
(throw 'done nil))
|
(throw 'done nil))
|
||||||
;; actions
|
;; actions
|
||||||
((setq action-cache (assoc char centaur-tabs-ace-dispatch-alist))
|
((setq action-cache (assoc char centuar-tabs-ace-dispatch-alist))
|
||||||
(setq action-cache (cadr action-cache))
|
(setq action-cache (cadr action-cache))
|
||||||
(cond ((eq action-cache 'exit) ; exit
|
(cond ((eq action-cache 'exit) ; exit
|
||||||
(message "Quit")
|
(message "Quit")
|
||||||
(throw 'done nil))
|
(throw 'done nil))
|
||||||
((eq action-cache 'forward-group) ; forward group
|
((eq action-cache 'forward-group) ; forward group
|
||||||
(message "Forward group")
|
(message "Forward group")
|
||||||
(centaur-tabs-forward-group)
|
(centaur-tabs-forward-group)
|
||||||
(centaur-tabs--dim-window))
|
(centaur-tabs--dim-window))
|
||||||
((eq action-cache 'backward-group) ; backward group
|
((eq action-cache 'backward-group) ; backward group
|
||||||
(message "Backward group")
|
(message "Backward group")
|
||||||
(centaur-tabs-backward-group)
|
(centaur-tabs-backward-group)
|
||||||
(centaur-tabs--dim-window))
|
(centaur-tabs--dim-window))
|
||||||
((eq action-cache 'show-help) ; help menu
|
((eq action-cache 'show-help) ; help menu
|
||||||
(message "%s" (mapconcat
|
(message "%s" (mapconcat
|
||||||
(lambda (elem) (format "%s: %s"
|
(lambda (elem) (format "%s: %s"
|
||||||
(key-description (vector (car elem)))
|
(key-description (vector (car elem)))
|
||||||
(caddr elem)))
|
(caddr elem)))
|
||||||
centaur-tabs-ace-dispatch-alist
|
centuar-tabs-ace-dispatch-alist
|
||||||
"\n")))
|
"\n")))
|
||||||
(t (setq action action-cache) ; other actions
|
(t (setq action action-cache) ; other actions
|
||||||
(cond ((eq action-cache 'jump-to-tab)
|
(cond ((eq action-cache 'jump-to-tab)
|
||||||
(message "Jump to tab: "))
|
(message "Jump to tab: "))
|
||||||
((eq action-cache 'close-tab)
|
((eq action-cache 'close-tab)
|
||||||
(message "Close tab: "))
|
(message "Close tab: "))
|
||||||
((eq action-cache 'swap-tab)
|
((eq action-cache 'swap-tab)
|
||||||
(message "Swap current tab with: "))))))
|
(message "Swap current tab with: "))))))
|
||||||
;; no match, repeat
|
;; no match, repeat
|
||||||
(t
|
(t
|
||||||
(message "No such candidate: %s, hit ? for help." (key-description (vector char)))))))))
|
(message "No such candidate: %s, hit ? for help." (key-description (vector char)))))))))
|
||||||
(centaur-tabs-set-template (centaur-tabs-current-tabset t) nil)
|
(centaur-tabs-set-template (centaur-tabs-current-tabset t) nil)
|
||||||
(when centaur-tabs-ace-jump-dim-buffer
|
(when centaur-tabs-ace-jump-dim-buffer
|
||||||
(delete-overlay centaur-tabs-dim-overlay)
|
(delete-overlay centaur-tabs-dim-overlay)
|
||||||
|
@ -388,19 +357,21 @@ ACTION has to be one of value in `centaur-tabs-ace-dispatch-alist'"
|
||||||
(centaur-tabs-display-update)))
|
(centaur-tabs-display-update)))
|
||||||
|
|
||||||
(defun centaur-tabs-ace-jump (&optional arg)
|
(defun centaur-tabs-ace-jump (&optional arg)
|
||||||
"Select a tab and perform an action. Ace-jump style.
|
"Select a tab and perform an action. Ace-jump style.
|
||||||
If no ARG is provided, select that tab. If prefixed with one
|
If no ARG is provided, select that tab.
|
||||||
`universal-argument', swap the current tab with the selected tab.
|
If prefixed with one `universal-argument', swap the current
|
||||||
If prefixed with two `universal-argument's, close selected tab."
|
tab with the selected tab.
|
||||||
|
If prefixed with two `universal-argument's, close
|
||||||
|
selected tab."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(cond ((eq arg 1)
|
(cond ((eq arg 1)
|
||||||
(centaur-tabs-ace-action 'jump-to-tab))
|
(centaur-tabs-ace-action 'jump-to-tab))
|
||||||
((eq arg 4)
|
((eq arg 4)
|
||||||
(centaur-tabs-ace-action 'swap-tab))
|
(centaur-tabs-ace-action 'swap-tab))
|
||||||
((eq arg 16)
|
((eq arg 16)
|
||||||
(centaur-tabs-ace-action 'close-tab))
|
(centaur-tabs-ace-action 'close-tab))
|
||||||
(t
|
(t
|
||||||
(centaur-tabs-ace-action 'jump-to-tab))))
|
(centaur-tabs-ace-action 'jump-to-tab))))
|
||||||
|
|
||||||
(defun centaur-tabs-group-buffer-groups ()
|
(defun centaur-tabs-group-buffer-groups ()
|
||||||
"Use centaur-tabs's own buffer grouping function."
|
"Use centaur-tabs's own buffer grouping function."
|
||||||
|
@ -419,24 +390,21 @@ Should be buffer local and speed up calculation of buffer groups.")
|
||||||
(symbol-value 'centaur-tabs-projectile-buffer-group-calc)
|
(symbol-value 'centaur-tabs-projectile-buffer-group-calc)
|
||||||
(set (make-local-variable 'centaur-tabs-projectile-buffer-group-calc)
|
(set (make-local-variable 'centaur-tabs-projectile-buffer-group-calc)
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
((or (get-buffer-process (current-buffer)) (memq major-mode '(comint-mode compilation-mode))) '("Term"))
|
((or (get-buffer-process (current-buffer)) (memq major-mode '(comint-mode compilation-mode))) '("Term"))
|
||||||
((string-equal "*" (substring (buffer-name) 0 1)) '("Misc"))
|
((string-equal "*" (substring (buffer-name) 0 1)) '("Misc"))
|
||||||
((condition-case _err
|
((condition-case _err
|
||||||
(projectile-project-root)
|
(projectile-project-root)
|
||||||
(error nil))
|
(error nil)) (list (projectile-project-name)))
|
||||||
(list (projectile-project-name)))
|
((memq major-mode '(emacs-lisp-mode python-mode emacs-lisp-mode c-mode
|
||||||
((memq major-mode '(emacs-lisp-mode python-mode emacs-lisp-mode c-mode
|
c++-mode javascript-mode js-mode
|
||||||
c++-mode javascript-mode js-mode
|
js2-mode makefile-mode
|
||||||
js2-mode makefile-mode
|
lua-mode vala-mode)) '("Coding"))
|
||||||
lua-mode vala-mode))
|
((memq major-mode '(nxhtml-mode html-mode
|
||||||
'("Coding"))
|
mhtml-mode css-mode)) '("HTML"))
|
||||||
((memq major-mode '( nxhtml-mode html-mode
|
((memq major-mode '(org-mode calendar-mode diary-mode)) '("Org"))
|
||||||
mhtml-mode css-mode))
|
((memq major-mode '(dired-mode)) '("Dir"))
|
||||||
'("HTML"))
|
(t '("Other"))))
|
||||||
((memq major-mode '(org-mode calendar-mode diary-mode)) '("Org"))
|
|
||||||
((memq major-mode '(dired-mode)) '("Dir"))
|
|
||||||
(t '("Other"))))
|
|
||||||
(symbol-value 'centaur-tabs-projectile-buffer-group-calc)))
|
(symbol-value 'centaur-tabs-projectile-buffer-group-calc)))
|
||||||
|
|
||||||
(defun centaur-tabs-group-by-projectile-project()
|
(defun centaur-tabs-group-by-projectile-project()
|
||||||
|
@ -458,11 +426,11 @@ Should be buffer local and speed up calculation of buffer groups.")
|
||||||
"Display a list of current buffer groups in Helm."
|
"Display a list of current buffer groups in Helm."
|
||||||
(interactive)
|
(interactive)
|
||||||
(setq helm-source-centaur-tabs-group
|
(setq helm-source-centaur-tabs-group
|
||||||
(when (featurep 'helm)
|
(when (featurep 'helm)
|
||||||
(require 'helm)
|
(require 'helm)
|
||||||
(helm-build-sync-source "Centaur-Tabs Group"
|
(helm-build-sync-source "Centaur-Tabs Group"
|
||||||
:candidates #'centaur-tabs-get-groups
|
:candidates #'centaur-tabs-get-groups
|
||||||
:action '(("Switch to group" . centaur-tabs-switch-group))))))
|
:action '(("Switch to group" . centaur-tabs-switch-group))))))
|
||||||
|
|
||||||
;; Ivy source for switching group in ivy.
|
;; Ivy source for switching group in ivy.
|
||||||
|
|
||||||
|
@ -478,9 +446,9 @@ Should be buffer local and speed up calculation of buffer groups.")
|
||||||
:action #'centaur-tabs-switch-group
|
:action #'centaur-tabs-switch-group
|
||||||
:caller 'centaur-tabs-counsel-switch-group)))
|
:caller 'centaur-tabs-counsel-switch-group)))
|
||||||
|
|
||||||
|
|
||||||
(defun centaur-tabs-extract-window-to-new-frame()
|
(defun centaur-tabs-extract-window-to-new-frame()
|
||||||
"Kill the current window in the current frame, and open the current buffer
|
"Kill the current window in the current frame, and open the current buffer in a new frame."
|
||||||
in a new frame."
|
|
||||||
(interactive)
|
(interactive)
|
||||||
(unless (centaur-tabs--one-window-p)
|
(unless (centaur-tabs--one-window-p)
|
||||||
(let ((buffer (current-buffer)))
|
(let ((buffer (current-buffer)))
|
||||||
|
@ -494,11 +462,12 @@ in a new frame."
|
||||||
(let* ((filename (if (equal major-mode 'dired-mode)
|
(let* ((filename (if (equal major-mode 'dired-mode)
|
||||||
default-directory
|
default-directory
|
||||||
(buffer-file-name)))
|
(buffer-file-name)))
|
||||||
(filename (expand-file-name filename)))
|
(filename (expand-file-name filename)))
|
||||||
(when filename
|
(when filename
|
||||||
(kill-new filename)
|
(kill-new filename)
|
||||||
(message "Copied buffer file name '%s' to the kill ring." filename))))
|
(message "Copied buffer file name '%s' to the kill ring." filename))))
|
||||||
|
|
||||||
|
|
||||||
(defun centaur-tabs-open-directory-in-external-application ()
|
(defun centaur-tabs-open-directory-in-external-application ()
|
||||||
"Open the current directory in a external application."
|
"Open the current directory in a external application."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -507,7 +476,7 @@ in a new frame."
|
||||||
(defun centaur-tabs-open-in-external-application ()
|
(defun centaur-tabs-open-in-external-application ()
|
||||||
"Open the file of the current buffer according to its mime type."
|
"Open the file of the current buffer according to its mime type."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((path (or (buffer-file-name) default-directory)))
|
(let ((path (if (buffer-file-name) (buffer-file-name) default-directory)))
|
||||||
(centaur-tabs--open-externally path)))
|
(centaur-tabs--open-externally path)))
|
||||||
|
|
||||||
(defun centaur-tabs--open-externally (file-or-path)
|
(defun centaur-tabs--open-externally (file-or-path)
|
||||||
|
@ -523,9 +492,10 @@ Modified copy of `treemacs-visit-node-in-external-application`."
|
||||||
(shell-command (format "open \"%s\"" path)))
|
(shell-command (format "open \"%s\"" path)))
|
||||||
('gnu/linux
|
('gnu/linux
|
||||||
(let ((process-connection-type nil))
|
(let ((process-connection-type nil))
|
||||||
(start-process "" nil "xdg-open" path)))
|
(start-process "" nil "xdg-open" path)))
|
||||||
(_ (message "Don't know how to open files on %s." (symbol-name system-type))))))
|
(_ (message "Don't know how to open files on %s." (symbol-name system-type))))))
|
||||||
|
|
||||||
|
|
||||||
(defun centaur-tabs--copy-directory-name-to-clipboard ()
|
(defun centaur-tabs--copy-directory-name-to-clipboard ()
|
||||||
"Copy the current directory name to the clipboard."
|
"Copy the current directory name to the clipboard."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -537,17 +507,22 @@ Modified copy of `treemacs-visit-node-in-external-application`."
|
||||||
"Menu definition with a list of tab groups."
|
"Menu definition with a list of tab groups."
|
||||||
(mapcar (lambda (s) `[,s ,s]) (sort (centaur-tabs-get-groups) #'string<)))
|
(mapcar (lambda (s) `[,s ,s]) (sort (centaur-tabs-get-groups) #'string<)))
|
||||||
|
|
||||||
|
|
||||||
(defun centaur-tabs--tab-submenu-tabs-definition ()
|
(defun centaur-tabs--tab-submenu-tabs-definition ()
|
||||||
"Menu definition with a list of tabs for the current group."
|
"Menu definition with a list of tabs for the current group."
|
||||||
(let* ((tabset (centaur-tabs-get-tabset centaur-tabs-last-focused-buffer-group))
|
(let* ((tabset (centaur-tabs-get-tabset centaur-tabs-last-focused-buffer-group))
|
||||||
(tabs-in-group (centaur-tabs-tabs tabset))
|
(tabs-in-group (centaur-tabs-tabs tabset))
|
||||||
(buffers (mapcar #'centaur-tabs-tab-value tabs-in-group))
|
(buffers (mapcar #'centaur-tabs-tab-value tabs-in-group))
|
||||||
(sorted-tabnames (sort (mapcar #'buffer-name buffers) #'string<)))
|
(sorted-tabnames (sort (mapcar #'buffer-name buffers) #'string<)))
|
||||||
(mapcar (lambda (s) `[,s ,s]) sorted-tabnames)))
|
(mapcar (lambda (s) `[,s ,s]) sorted-tabnames)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defvar centaur-tabs--groups-submenu-key "Tab groups")
|
(defvar centaur-tabs--groups-submenu-key "Tab groups")
|
||||||
(defvar centaur-tabs--tabs-submenu-key "Go to tab of group")
|
(defvar centaur-tabs--tabs-submenu-key "Go to tab of group")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defun centaur-tabs--kill-this-buffer-dont-ask()
|
(defun centaur-tabs--kill-this-buffer-dont-ask()
|
||||||
"Kill the current buffer without confirmation."
|
"Kill the current buffer without confirmation."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -555,6 +530,7 @@ Modified copy of `treemacs-visit-node-in-external-application`."
|
||||||
(centaur-tabs-display-update)
|
(centaur-tabs-display-update)
|
||||||
(redisplay t))
|
(redisplay t))
|
||||||
|
|
||||||
|
|
||||||
(defun centaur-tabs--tab-menu-definition ()
|
(defun centaur-tabs--tab-menu-definition ()
|
||||||
"Definition of the context menu of a tab."
|
"Definition of the context menu of a tab."
|
||||||
`(["Kill this buffer" centaur-tabs--kill-this-buffer-dont-ask]
|
`(["Kill this buffer" centaur-tabs--kill-this-buffer-dont-ask]
|
||||||
|
@ -582,12 +558,13 @@ Modified copy of `treemacs-visit-node-in-external-application`."
|
||||||
:active default-directory]
|
:active default-directory]
|
||||||
"----"
|
"----"
|
||||||
,( append (list centaur-tabs--groups-submenu-key) (centaur-tabs--tab-submenu-groups-definition))
|
,( append (list centaur-tabs--groups-submenu-key) (centaur-tabs--tab-submenu-groups-definition))
|
||||||
,( append (list centaur-tabs--tabs-submenu-key) (centaur-tabs--tab-submenu-tabs-definition))))
|
,( append (list centaur-tabs--tabs-submenu-key) (centaur-tabs--tab-submenu-tabs-definition))
|
||||||
|
))
|
||||||
|
|
||||||
(defun centaur-tabs--one-window-p ()
|
(defun centaur-tabs--one-window-p ()
|
||||||
"Like `one-window-p`, but taking into account side windows like treemacs."
|
"Like `one-window-p`, but taking into account side windows like treemacs."
|
||||||
(let* ((mainwindow (window-main-window))
|
(let* ((mainwindow (window-main-window))
|
||||||
(child-count (window-child-count mainwindow)))
|
(child-count (window-child-count mainwindow)))
|
||||||
(= 0 child-count)))
|
(= 0 child-count)))
|
||||||
|
|
||||||
(defun centaur-tabs--get-tab-from-name (tabname)
|
(defun centaur-tabs--get-tab-from-name (tabname)
|
||||||
|
@ -597,46 +574,54 @@ Modified copy of `treemacs-visit-node-in-external-application`."
|
||||||
(lambda (tab) (string= tabname (buffer-name (centaur-tabs-tab-value tab))))
|
(lambda (tab) (string= tabname (buffer-name (centaur-tabs-tab-value tab))))
|
||||||
seq)))
|
seq)))
|
||||||
|
|
||||||
|
|
||||||
(defun centaur-tabs--tab-menu (event)
|
(defun centaur-tabs--tab-menu (event)
|
||||||
"Show a context menu for the clicked tab or button.
|
"Show a context menu for the clicked tab or button. The clicked tab, identified by EVENT, is selected."
|
||||||
The clicked tab, identified by EVENT, is selected."
|
|
||||||
(interactive "e" )
|
(interactive "e" )
|
||||||
|
|
||||||
(let ((click-on-tab-p (ignore-errors (centaur-tabs-get-tab-from-event event))))
|
(let ((click-on-tab-p (ignore-errors (centaur-tabs-get-tab-from-event event))))
|
||||||
|
|
||||||
(when (not click-on-tab-p)
|
(when (not click-on-tab-p)
|
||||||
(centaur-tabs--groups-menu))
|
(centaur-tabs--groups-menu))
|
||||||
|
|
||||||
(when click-on-tab-p
|
(when click-on-tab-p
|
||||||
(centaur-tabs-do-select event)
|
(centaur-tabs-do-select event)
|
||||||
(redisplay t)
|
(redisplay t)
|
||||||
|
|
||||||
(let*
|
(let*
|
||||||
((menu (easy-menu-create-menu nil (centaur-tabs--tab-menu-definition)))
|
((menu (easy-menu-create-menu nil (centaur-tabs--tab-menu-definition)))
|
||||||
(choice (x-popup-menu t menu))
|
(choice (x-popup-menu t menu))
|
||||||
(action (lookup-key menu (apply 'vector choice)))
|
(action (lookup-key menu (apply 'vector choice)))
|
||||||
(action-is-command-p (and (commandp action) (functionp action))))
|
(action-is-command-p (and (commandp action) (functionp action))))
|
||||||
(when action-is-command-p
|
(when action-is-command-p
|
||||||
(call-interactively action))
|
(call-interactively action))
|
||||||
(when (not action-is-command-p)
|
(when (not action-is-command-p)
|
||||||
(let* ((menu-key (cl-first choice))
|
(let* ((menu-key (first choice))
|
||||||
(choice-is-group-p (string= centaur-tabs--groups-submenu-key (symbol-name menu-key)))
|
(choice-is-group-p (string= centaur-tabs--groups-submenu-key (symbol-name menu-key)))
|
||||||
(name (car (last choice)))
|
(name (car (last choice)))
|
||||||
(name-as-string (symbol-name name)))
|
(name-as-string (symbol-name name)))
|
||||||
(if choice-is-group-p
|
(if choice-is-group-p
|
||||||
(centaur-tabs-switch-group name-as-string)
|
(centaur-tabs-switch-group name-as-string)
|
||||||
(switch-to-buffer name-as-string))))))))
|
(switch-to-buffer name-as-string))))))))
|
||||||
|
|
||||||
|
|
||||||
(defun centaur-tabs--groups-menu ()
|
(defun centaur-tabs--groups-menu ()
|
||||||
"Show a popup menu with the centaur tabs groups."
|
"Show a popup menu with the centaur tabs groups."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((sorted-groups (centaur-tabs--tab-submenu-groups-definition))
|
|
||||||
(menu (easy-menu-create-menu "Tab groups"
|
(let*
|
||||||
(centaur-tabs--tab-submenu-groups-definition)))
|
((sorted-groups (centaur-tabs--tab-submenu-groups-definition))
|
||||||
(choice (x-popup-menu t menu))
|
(menu (easy-menu-create-menu "Tab groups" (centaur-tabs--tab-submenu-groups-definition)))
|
||||||
(action (lookup-key menu (apply 'vector choice)))
|
(choice (x-popup-menu t menu))
|
||||||
(action-is-command-p (and (commandp action) (functionp action))))
|
(action (lookup-key menu (apply 'vector choice)))
|
||||||
|
(action-is-command-p (and (commandp action) (functionp action))))
|
||||||
(when action-is-command-p
|
(when action-is-command-p
|
||||||
(call-interactively action))
|
(call-interactively action))
|
||||||
(when (not action-is-command-p)
|
(when (not action-is-command-p)
|
||||||
(let ((group (car (last choice))))
|
(let ((group (car (last choice))))
|
||||||
(centaur-tabs-switch-group (format "%s" group))))))
|
(centaur-tabs-switch-group (format "%s" group))))))
|
||||||
|
|
||||||
|
|
||||||
(provide 'centaur-tabs-interactive)
|
(provide 'centaur-tabs-interactive)
|
||||||
|
|
||||||
;;; centaur-tabs-interactive.el ends here
|
;;; centaur-tabs-interactive.el ends here
|
14
code/elpa/centaur-tabs-20230607.1501/centaur-tabs-pkg.el
Normal file
14
code/elpa/centaur-tabs-20230607.1501/centaur-tabs-pkg.el
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
(define-package "centaur-tabs" "20230607.1501" "Aesthetic, modern looking customizable tabs plugin"
|
||||||
|
'((emacs "24.4")
|
||||||
|
(powerline "2.4")
|
||||||
|
(cl-lib "0.5"))
|
||||||
|
:commit "0bb1aa18d475319df85f192dce3327802866c3c3" :authors
|
||||||
|
'(("Emmanuel Bustos" . "ema2159@gmail.com"))
|
||||||
|
:maintainers
|
||||||
|
'(("Emmanuel Bustos" . "ema2159@gmail.com"))
|
||||||
|
:maintainer
|
||||||
|
'("Emmanuel Bustos" . "ema2159@gmail.com")
|
||||||
|
:url "https://github.com/ema2159/centaur-tabs")
|
||||||
|
;; Local Variables:
|
||||||
|
;; no-byte-compile: t
|
||||||
|
;; End:
|
|
@ -1,18 +1,18 @@
|
||||||
;;; centaur-tabs.el --- Aesthetic, modern looking customizable tabs plugin -*- lexical-binding: t; -*-
|
;;; centaur-tabs.el --- Aesthetic, modern looking customizable tabs plugin -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2019-2024 Emmanuel Bustos
|
;; Copyright (C) 2019 Emmanuel Bustos
|
||||||
;; Copyright (C) 2024 Jen-Chieh Shen
|
|
||||||
|
|
||||||
;; Filename: centaur-tabs.el
|
;; Filename: centaur-tabs.el
|
||||||
;; Description: Provide an out of box configuration to use highly customizable tabs.
|
;; Description: Provide an out of box configuration to use highly customizable tabs.
|
||||||
;; URL: https://github.com/ema2159/centaur-tabs
|
;; URL: https://github.com/ema2159/centaur-tabs
|
||||||
;; Author: Emmanuel Bustos <ema2159@gmail.com>
|
;; Author: Emmanuel Bustos <ema2159@gmail.com>
|
||||||
;; Maintainer: Jen-Chieh Shen <jcs090218@gmail.com>
|
;; Maintainer: Emmanuel Bustos <ema2159@gmail.com>
|
||||||
;; Created: 2019-21-19 22:14:34
|
;; Created: 2019-21-19 22:14:34
|
||||||
;; Version: 3.3
|
;; Version: 5
|
||||||
;; Known Compatibility: GNU Emacs 26.2
|
;; Known Compatibility: GNU Emacs 26.2
|
||||||
;; Package-Requires: ((emacs "27.1") (powerline "2.4"))
|
;; Package-Requires: ((emacs "24.4") (powerline "2.4") (cl-lib "0.5"))
|
||||||
;; Keywords: frames
|
;;
|
||||||
|
;;
|
||||||
|
|
||||||
;;; This file is NOT part of GNU Emacs
|
;;; This file is NOT part of GNU Emacs
|
||||||
|
|
||||||
|
@ -54,15 +54,10 @@
|
||||||
;;
|
;;
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
;;; Requires
|
||||||
(require 'centaur-tabs-elements)
|
(require 'centaur-tabs-elements)
|
||||||
(require 'centaur-tabs-functions)
|
(require 'centaur-tabs-functions)
|
||||||
(require 'centaur-tabs-interactive)
|
(require 'centaur-tabs-interactive)
|
||||||
|
|
||||||
;; Compiler pacifier
|
|
||||||
(declare-function undo-tree-undo-1 "ext:undo-tree.el")
|
|
||||||
(declare-function undo-tree-redo-1 "ext:undo-tree.el")
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;; Centaur-Tabs source code ;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;; Centaur-Tabs source code ;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defgroup centaur-tabs nil
|
(defgroup centaur-tabs nil
|
||||||
|
@ -71,17 +66,15 @@
|
||||||
|
|
||||||
(defvar centaur-tabs--buffer-show-groups nil)
|
(defvar centaur-tabs--buffer-show-groups nil)
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Minor modes
|
;;; Minor modes
|
||||||
|
;;
|
||||||
(defsubst centaur-tabs-mode-on-p ()
|
(defsubst centaur-tabs-mode-on-p ()
|
||||||
"Return non-nil if Centaur-Tabs mode is on."
|
"Return non-nil if Centaur-Tabs mode is on."
|
||||||
(eq (default-value centaur-tabs-display-line-format)
|
(eq (default-value centaur-tabs-display-line-format)
|
||||||
centaur-tabs-header-line-format))
|
centaur-tabs-header-line-format))
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Centaur-Tabs-Local mode
|
;;; Centaur-Tabs-Local mode
|
||||||
|
;;
|
||||||
(defvar centaur-tabs--local-hlf nil)
|
(defvar centaur-tabs--local-hlf nil)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
|
@ -100,24 +93,24 @@ hidden, it is shown again. Signal an error if Centaur-Tabs mode is off."
|
||||||
;;; ON
|
;;; ON
|
||||||
(if centaur-tabs-local-mode
|
(if centaur-tabs-local-mode
|
||||||
(if (and (local-variable-p centaur-tabs-display-line-format)
|
(if (and (local-variable-p centaur-tabs-display-line-format)
|
||||||
(eval centaur-tabs-display-line-format))
|
(eval centaur-tabs-display-line-format))
|
||||||
;; A local header line exists, hide it to show the tab bar.
|
;; A local header line exists, hide it to show the tab bar.
|
||||||
(progn
|
(progn
|
||||||
;; Fail in case of an inconsistency because another local
|
;; Fail in case of an inconsistency because another local
|
||||||
;; header line is already hidden.
|
;; header line is already hidden.
|
||||||
(when (local-variable-p 'centaur-tabs--local-hlf)
|
(when (local-variable-p 'centaur-tabs--local-hlf)
|
||||||
(error "Another local header line is already hidden"))
|
(error "Another local header line is already hidden"))
|
||||||
(set (make-local-variable 'centaur-tabs--local-hlf)
|
(set (make-local-variable 'centaur-tabs--local-hlf)
|
||||||
(eval centaur-tabs-display-line-format))
|
(eval centaur-tabs-display-line-format))
|
||||||
(kill-local-variable centaur-tabs-display-line-format))
|
(kill-local-variable centaur-tabs-display-line-format))
|
||||||
;; Otherwise hide the tab bar in this buffer.
|
;; Otherwise hide the tab bar in this buffer.
|
||||||
(set centaur-tabs-display-line-format nil))
|
(set centaur-tabs-display-line-format nil))
|
||||||
;;; OFF
|
;;; OFF
|
||||||
(if (local-variable-p 'centaur-tabs--local-hlf)
|
(if (local-variable-p 'centaur-tabs--local-hlf)
|
||||||
;; A local header line is hidden, show it again.
|
;; A local header line is hidden, show it again.
|
||||||
(progn
|
(progn
|
||||||
(set centaur-tabs-display-line-format centaur-tabs--local-hlf)
|
(set centaur-tabs-display-line-format centaur-tabs--local-hlf)
|
||||||
(kill-local-variable 'centaur-tabs--local-hlf))
|
(kill-local-variable 'centaur-tabs--local-hlf))
|
||||||
;; The tab bar is locally hidden, show it again.
|
;; The tab bar is locally hidden, show it again.
|
||||||
(kill-local-variable centaur-tabs-display-line-format))))
|
(kill-local-variable centaur-tabs-display-line-format))))
|
||||||
|
|
||||||
|
@ -139,92 +132,87 @@ Returns non-nil if the new state is enabled.
|
||||||
(if centaur-tabs-mode
|
(if centaur-tabs-mode
|
||||||
;;; ON
|
;;; ON
|
||||||
(unless (centaur-tabs-mode-on-p)
|
(unless (centaur-tabs-mode-on-p)
|
||||||
;; Save current default value of `centaur-tabs-display-line-format'.
|
;; Save current default value of `centaur-tabs-display-line-format'.
|
||||||
(setq centaur-tabs--global-hlf (default-value centaur-tabs-display-line-format))
|
(setq centaur-tabs--global-hlf (default-value centaur-tabs-display-line-format))
|
||||||
(centaur-tabs-init-tabsets-store)
|
(centaur-tabs-init-tabsets-store)
|
||||||
(set-default centaur-tabs-display-line-format centaur-tabs-header-line-format))
|
(set-default centaur-tabs-display-line-format centaur-tabs-header-line-format))
|
||||||
;;; OFF
|
;;; OFF
|
||||||
(when (centaur-tabs-mode-on-p)
|
(when (centaur-tabs-mode-on-p)
|
||||||
;; Turn off Centaur-Tabs-Local mode globally.
|
;; Turn off Centaur-Tabs-Local mode globally.
|
||||||
(mapc #'(lambda (b)
|
(mapc #'(lambda (b)
|
||||||
(condition-case nil
|
(condition-case nil
|
||||||
(with-current-buffer b
|
(with-current-buffer b
|
||||||
(and centaur-tabs-local-mode
|
(and centaur-tabs-local-mode
|
||||||
(centaur-tabs-local-mode -1)))
|
(centaur-tabs-local-mode -1)))
|
||||||
(error nil)))
|
(error nil)))
|
||||||
(buffer-list))
|
(buffer-list))
|
||||||
;; Restore previous `centaur-tabs-display-line-format'.
|
;; Restore previous `centaur-tabs-display-line-format'.
|
||||||
(set-default centaur-tabs-display-line-format centaur-tabs--global-hlf)
|
(set-default centaur-tabs-display-line-format centaur-tabs--global-hlf)
|
||||||
(centaur-tabs-free-tabsets-store)))
|
(centaur-tabs-free-tabsets-store))
|
||||||
;; Make sure it refresh every windows!
|
))
|
||||||
(force-window-update))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Tab bar buffer setup
|
;;; Tab bar buffer setup
|
||||||
|
;;
|
||||||
(defun centaur-tabs-buffer-init ()
|
(defun centaur-tabs-buffer-init ()
|
||||||
"Initialize tab bar buffer data.
|
"Initialize tab bar buffer data.
|
||||||
Run as `centaur-tabs-init-hook'."
|
Run as `centaur-tabs-init-hook'."
|
||||||
(setq centaur-tabs--buffers nil
|
(setq centaur-tabs--buffers nil
|
||||||
centaur-tabs-current-tabset-function 'centaur-tabs-buffer-tabs
|
centaur-tabs-current-tabset-function 'centaur-tabs-buffer-tabs
|
||||||
centaur-tabs-tab-label-function 'centaur-tabs-buffer-tab-label
|
centaur-tabs-tab-label-function 'centaur-tabs-buffer-tab-label
|
||||||
centaur-tabs-select-tab-function 'centaur-tabs-buffer-select-tab)
|
centaur-tabs-select-tab-function 'centaur-tabs-buffer-select-tab
|
||||||
|
)
|
||||||
;; If set, initialize selected overline
|
;; If set, initialize selected overline
|
||||||
(when (eq centaur-tabs-set-bar 'under)
|
(when (eq centaur-tabs-set-bar 'under)
|
||||||
(set-face-attribute 'centaur-tabs-selected nil
|
(set-face-attribute 'centaur-tabs-selected nil
|
||||||
:underline (face-background 'centaur-tabs-active-bar-face nil 'default)
|
:underline (face-background 'centaur-tabs-active-bar-face nil 'default)
|
||||||
:overline nil)
|
:overline nil)
|
||||||
(set-face-attribute 'centaur-tabs-selected-modified nil
|
(set-face-attribute 'centaur-tabs-selected-modified nil
|
||||||
:underline (face-background 'centaur-tabs-active-bar-face nil 'default)
|
:underline (face-background 'centaur-tabs-active-bar-face nil 'default)
|
||||||
:overline nil)
|
:overline nil)
|
||||||
(set-face-attribute 'centaur-tabs-unselected nil
|
(set-face-attribute 'centaur-tabs-unselected nil
|
||||||
:underline nil
|
:underline nil
|
||||||
:overline nil)
|
:overline nil)
|
||||||
(set-face-attribute 'centaur-tabs-unselected-modified nil
|
(set-face-attribute 'centaur-tabs-unselected-modified nil
|
||||||
:underline nil
|
:underline nil
|
||||||
:overline nil))
|
:overline nil))
|
||||||
(when (eq centaur-tabs-set-bar 'over)
|
(when (eq centaur-tabs-set-bar 'over)
|
||||||
(set-face-attribute 'centaur-tabs-selected nil
|
(set-face-attribute 'centaur-tabs-selected nil
|
||||||
:overline (face-background 'centaur-tabs-active-bar-face nil 'default)
|
:overline (face-background 'centaur-tabs-active-bar-face nil 'default)
|
||||||
:underline nil)
|
:underline nil)
|
||||||
(set-face-attribute 'centaur-tabs-selected-modified nil
|
(set-face-attribute 'centaur-tabs-selected-modified nil
|
||||||
:overline (face-background 'centaur-tabs-active-bar-face nil 'default)
|
:overline (face-background 'centaur-tabs-active-bar-face nil 'default)
|
||||||
:underline nil)
|
:underline nil)
|
||||||
(set-face-attribute 'centaur-tabs-unselected nil
|
(set-face-attribute 'centaur-tabs-unselected nil
|
||||||
:overline nil
|
:overline nil
|
||||||
:underline nil)
|
:underline nil)
|
||||||
(set-face-attribute 'centaur-tabs-unselected-modified nil
|
(set-face-attribute 'centaur-tabs-unselected-modified nil
|
||||||
:overline nil
|
:overline nil
|
||||||
:underline nil))
|
:underline nil))
|
||||||
(add-function :after after-focus-change-function #'centaur-tabs-after-focus)
|
|
||||||
(add-hook 'window-buffer-change-functions #'centaur-tabs-on-window-buffer-change)
|
|
||||||
(add-hook 'after-save-hook #'centaur-tabs-on-saving-buffer)
|
(add-hook 'after-save-hook #'centaur-tabs-on-saving-buffer)
|
||||||
(add-hook 'first-change-hook #'centaur-tabs-on-modifying-buffer)
|
(add-hook 'first-change-hook #'centaur-tabs-on-modifying-buffer)
|
||||||
(add-hook 'kill-buffer-hook #'centaur-tabs-buffer-track-killed)
|
(add-hook 'kill-buffer-hook #'centaur-tabs-buffer-track-killed)
|
||||||
(advice-add #'undo :after #'centaur-tabs-on-modifying-buffer)
|
(advice-add #'undo :after #'centaur-tabs-after-modifying-buffer)
|
||||||
(advice-add #'undo-tree-undo-1 :after #'centaur-tabs-on-modifying-buffer)
|
(advice-add #'undo-tree-undo-1 :after #'centaur-tabs-after-modifying-buffer)
|
||||||
(advice-add #'undo-tree-redo-1 :after #'centaur-tabs-on-modifying-buffer)
|
(advice-add #'undo-tree-redo-1 :after #'centaur-tabs-after-modifying-buffer))
|
||||||
(advice-add 'load-theme :after #'centaur-tabs--after-load-theme))
|
|
||||||
|
|
||||||
(defun centaur-tabs-buffer-quit ()
|
(defun centaur-tabs-buffer-quit ()
|
||||||
"Quit tab bar buffer.
|
"Quit tab bar buffer.
|
||||||
Run as `centaur-tabs-quit-hook'."
|
Run as `centaur-tabs-quit-hook'."
|
||||||
(setq centaur-tabs--buffers nil
|
(setq centaur-tabs--buffers nil
|
||||||
centaur-tabs-current-tabset-function nil
|
centaur-tabs-current-tabset-function nil
|
||||||
centaur-tabs-tab-label-function nil
|
centaur-tabs-tab-label-function nil
|
||||||
centaur-tabs-select-tab-function nil)
|
centaur-tabs-select-tab-function nil
|
||||||
(remove-function after-focus-change-function #'centaur-tabs-after-focus)
|
)
|
||||||
(remove-hook 'window-buffer-change-functions #'centaur-tabs-on-window-buffer-change)
|
(remove-hook 'after-save-hook 'centaur-tabs-after-modifying-buffer)
|
||||||
(remove-hook 'after-save-hook 'centaur-tabs-on-modifying-buffer)
|
|
||||||
(remove-hook 'first-change-hook 'centaur-tabs-on-modifying-buffer)
|
(remove-hook 'first-change-hook 'centaur-tabs-on-modifying-buffer)
|
||||||
(remove-hook 'kill-buffer-hook 'centaur-tabs-buffer-track-killed)
|
(remove-hook 'kill-buffer-hook 'centaur-tabs-buffer-track-killed)
|
||||||
(advice-remove #'undo #'centaur-tabs-on-modifying-buffer)
|
(advice-remove #'undo #'centaur-tabs-after-modifying-buffer)
|
||||||
(advice-remove #'undo-tree-undo-1 #'centaur-tabs-on-modifying-buffer)
|
(advice-remove #'undo-tree-undo-1 #'centaur-tabs-after-modifying-buffer)
|
||||||
(advice-remove #'undo-tree-redo-1 #'centaur-tabs-on-modifying-buffer)
|
(advice-remove #'undo-tree-redo-1 #'centaur-tabs-after-modifying-buffer))
|
||||||
(advice-remove 'load-theme #'centaur-tabs--after-load-theme))
|
|
||||||
|
|
||||||
(add-hook 'centaur-tabs-init-hook #'centaur-tabs-buffer-init)
|
(add-hook 'centaur-tabs-init-hook #'centaur-tabs-buffer-init)
|
||||||
(add-hook 'centaur-tabs-quit-hook #'centaur-tabs-buffer-quit)
|
(add-hook 'centaur-tabs-quit-hook #'centaur-tabs-buffer-quit)
|
||||||
|
|
||||||
(provide 'centaur-tabs)
|
(provide 'centaur-tabs)
|
||||||
|
|
||||||
;;; centaur-tabs.el ends here
|
;;; centaur-tabs.el ends here
|
|
@ -1,891 +0,0 @@
|
||||||
;;; centaur-tabs-elements.el --- centaur-tabs visual components and customizations -*- lexical-binding: t; -*-
|
|
||||||
|
|
||||||
;; Copyright (C) 2019-2024 Emmanuel Bustos
|
|
||||||
;; Copyright (C) 2024 Jen-Chieh Shen
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or
|
|
||||||
;; modify it under the terms of the GNU General Public License as
|
|
||||||
;; published by the Free Software Foundation; either version 2, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
;;
|
|
||||||
;; This program is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
;; General Public License for more details.
|
|
||||||
;;
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with this program; see the file COPYING. If not, write to
|
|
||||||
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
||||||
;; Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
;;
|
|
||||||
;; This file contains the visual components of centaur-tabs
|
|
||||||
;;
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'custom)
|
|
||||||
(require 'color)
|
|
||||||
(require 'powerline)
|
|
||||||
|
|
||||||
;; Compiler pacifier
|
|
||||||
(declare-function all-the-icons-icon-for-file "ext:all-the-icons.el" t t)
|
|
||||||
(declare-function all-the-icons-icon-for-mode "ext:all-the-icons.el" t t)
|
|
||||||
(declare-function nerd-icons-icon-for-file "ext:nerd-icons.el" t t)
|
|
||||||
(declare-function nerd-icons-icon-for-mode "ext:nerd-icons.el" t t)
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Faces
|
|
||||||
|
|
||||||
(defface centaur-tabs-default
|
|
||||||
'((t (:background "black" :foreground "black")))
|
|
||||||
"Default face used in the tab bar."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-unselected
|
|
||||||
'((t (:background "#3D3C3D" :foreground "grey50")))
|
|
||||||
"Face used for unselected tabs."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-selected
|
|
||||||
'((t (:background "#31343E" :foreground "white")))
|
|
||||||
"Face used for the selected tab."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-unselected-modified
|
|
||||||
'((t (:background "#3D3C3D" :foreground "grey50")))
|
|
||||||
"Face used for unselected-modified tabs."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-selected-modified
|
|
||||||
'((t (:background "#31343E" :foreground "white")))
|
|
||||||
"Face used for the selected-modified tab."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-close-unselected
|
|
||||||
'((t (:inherit centaur-tabs-unselected)))
|
|
||||||
"Face used for unselected close button."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-close-selected
|
|
||||||
'((t (:inherit centaur-tabs-selected)))
|
|
||||||
"Face used for selected close button."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-name-mouse-face
|
|
||||||
'((t nil))
|
|
||||||
"Face used for tab name when hovered with the mouse."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-close-mouse-face
|
|
||||||
'((t (:inherit underline)))
|
|
||||||
"Face used for close button when hovered with the mouse."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-modified-marker-selected
|
|
||||||
`((t (:inherit centaur-tabs-selected)))
|
|
||||||
"Face used for selected modified marker."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-modified-marker-unselected
|
|
||||||
`((t (:inherit centaur-tabs-unselected)))
|
|
||||||
"Face used for unselected modified marker."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-active-bar-face
|
|
||||||
'((t (:background "cyan")))
|
|
||||||
"Face used for selected tab bar."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-jump-identifier-selected
|
|
||||||
'((t (:inherit centaur-tabs-modified-marker-selected :weight extra-bold)))
|
|
||||||
"Face used for selected tab identifiers when centaur-tabs-ace-jump is invoked."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-jump-identifier-unselected
|
|
||||||
'((t (:inherit centaur-tabs-modified-marker-unselected :weight extra-bold)))
|
|
||||||
"Face used for unselected tab identifiers when centaur-tabs-ace-jump is invoked."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defface centaur-tabs-dim-buffer-face
|
|
||||||
'((t (:foreground "gray40")))
|
|
||||||
"Face for the buffer when centaur-tabs-ace-jump is invoked."
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Tabs' display line
|
|
||||||
|
|
||||||
(defvar centaur-tabs-display-line
|
|
||||||
(if (boundp 'tab-line-format)
|
|
||||||
'tab-line
|
|
||||||
'header-line))
|
|
||||||
|
|
||||||
(defvar centaur-tabs-display-line-format
|
|
||||||
(if (boundp 'tab-line-format)
|
|
||||||
'tab-line-format
|
|
||||||
'header-line-format))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Tabs' characteristics
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-style "bar"
|
|
||||||
"The style of tab."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-label-fixed-length 0
|
|
||||||
"Fixed length of label. Set to 0 if dynamic."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'int)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-background-color
|
|
||||||
(face-background 'centaur-tabs-default nil 'default)
|
|
||||||
"*Background color of the tab bar.
|
|
||||||
By default, use the background color specified for the
|
|
||||||
`centaur-tabs-default' face (or inherited from another face), or the
|
|
||||||
background color of the `default' face otherwise."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'face)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-height 22
|
|
||||||
"The height of tab."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'int)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-bar-height (+ 8 centaur-tabs-height)
|
|
||||||
"The height of bar."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'int)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-mouse-pointer 'hand
|
|
||||||
"Cursor to display when hovering the tabs.
|
|
||||||
Default is `'hand'. The following scopes are possible:
|
|
||||||
- arrow
|
|
||||||
- hand
|
|
||||||
- vdrag
|
|
||||||
- hdrag
|
|
||||||
- modeline
|
|
||||||
- hourglass"
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'variable)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-set-bar nil
|
|
||||||
"When non nil, display a bar to show the currently selected tab.
|
|
||||||
There are three options:
|
|
||||||
- `'left': displays the bar at the left of the currently selected tab.
|
|
||||||
- `'under': displays the bar under the currently selected tab.
|
|
||||||
- `'over': displays the bar over the currently selected tab."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type '(choice :tag "Display bar at..."
|
|
||||||
(const :tag "Put bar on the left" left)
|
|
||||||
(const :tag "Put bar as an underline" under)
|
|
||||||
(const :tag "Put bar as an overline" over)))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Icons
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-set-icons nil
|
|
||||||
"When non nil, display an icon based on `centaur-tabs-icon-type' alongside
|
|
||||||
the tab name."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-icon-type (and centaur-tabs-set-icons
|
|
||||||
(or (require 'all-the-icons nil t)
|
|
||||||
(require 'nerd-icons nil t)))
|
|
||||||
"Icon type; it should be one of `all-the-icons' and `nerd-icons'."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'symbol
|
|
||||||
:set
|
|
||||||
(lambda (k v)
|
|
||||||
(pcase v
|
|
||||||
('all-the-icons
|
|
||||||
(unless (require 'all-the-icons nil t)
|
|
||||||
(setq v nil)))
|
|
||||||
('nerd-icons
|
|
||||||
(unless (require 'nerd-icons nil t)
|
|
||||||
(setq v nil)))
|
|
||||||
('type
|
|
||||||
(if (require 'all-the-icons nil t)
|
|
||||||
(setq v 'all-the-icons)
|
|
||||||
(setq v nil))))
|
|
||||||
(set k v)))
|
|
||||||
|
|
||||||
(defvar centaur-tabs-icon-scale-factor 1.0
|
|
||||||
"The base scale factor for the `height' face property of tab icons.")
|
|
||||||
|
|
||||||
(defvar centaur-tabs-icon-v-adjust 0.01
|
|
||||||
"The vertical adjust for tab icons.")
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-gray-out-icons nil
|
|
||||||
"When non nil, enable gray icons for unselected buffer."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type '(choice :tag "Gray out icons for unselected..."
|
|
||||||
(const :tag "Buffer" buffer)))
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-plain-icons nil
|
|
||||||
"When non nil, tab icons' color will be the same as tabs' foreground color."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-icons-prefix " "
|
|
||||||
"Prefix string before icons."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defun centaur-tabs--icon-for-file (file &rest args)
|
|
||||||
"Get the formatted icon for FILE.
|
|
||||||
ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties."
|
|
||||||
(pcase centaur-tabs-icon-type
|
|
||||||
('all-the-icons (apply #'all-the-icons-icon-for-file file args))
|
|
||||||
('nerd-icons (apply #'nerd-icons-icon-for-file file args))))
|
|
||||||
|
|
||||||
(defun centaur-tabs--icon-for-mode (mode &rest args)
|
|
||||||
"Get the formatted icon for MODE.
|
|
||||||
|
|
||||||
ARGS should be a plist containining `:height', `:v-adjust' or `:face' properties
|
|
||||||
like in the normal icon inserting functions."
|
|
||||||
(pcase centaur-tabs-icon-type
|
|
||||||
('all-the-icons (apply #'all-the-icons-icon-for-mode mode args))
|
|
||||||
('nerd-icons (apply #'nerd-icons-icon-for-mode mode args))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-icon (tab face selected)
|
|
||||||
"Generate icon for TAB using FACE's background.
|
|
||||||
If icon gray out option enabled, gray out icon if not SELECTED."
|
|
||||||
(if centaur-tabs-icon-type
|
|
||||||
(with-current-buffer (car tab)
|
|
||||||
(let* ((icon
|
|
||||||
(or (ignore-errors
|
|
||||||
(centaur-tabs--icon-for-file
|
|
||||||
(file-name-nondirectory (buffer-file-name))
|
|
||||||
:v-adjust centaur-tabs-icon-v-adjust
|
|
||||||
:height centaur-tabs-icon-scale-factor))
|
|
||||||
(ignore-errors
|
|
||||||
(centaur-tabs--icon-for-mode
|
|
||||||
major-mode
|
|
||||||
:v-adjust centaur-tabs-icon-v-adjust
|
|
||||||
:height centaur-tabs-icon-scale-factor))))
|
|
||||||
(background (face-background face nil 'default))
|
|
||||||
(inactive (cond ((and (not selected)
|
|
||||||
(eq centaur-tabs-gray-out-icons 'buffer))
|
|
||||||
(face-foreground 'mode-line-inactive nil 'default))
|
|
||||||
(centaur-tabs-plain-icons
|
|
||||||
(face-foreground 'centaur-tabs-selected nil 'default))
|
|
||||||
(t 'unspecified)))
|
|
||||||
(underline (and (eq (if (display-graphic-p) centaur-tabs-set-bar) 'under)
|
|
||||||
(face-attribute face :underline)))
|
|
||||||
(overline (and (eq (if (display-graphic-p) centaur-tabs-set-bar) 'over)
|
|
||||||
(face-attribute face :overline))))
|
|
||||||
(if (stringp icon)
|
|
||||||
(progn
|
|
||||||
(propertize icon 'face `(:inherit ,(get-text-property 0 'face icon)
|
|
||||||
:foreground ,inactive
|
|
||||||
:background ,background
|
|
||||||
:underline ,underline
|
|
||||||
:overline ,overline)))
|
|
||||||
"")))
|
|
||||||
""))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Ace-window style tab switching
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-show-jump-identifier 'prompted
|
|
||||||
"Whether to show the tab identifier for centaur-tabs-ace-jump.
|
|
||||||
It has 3 options:
|
|
||||||
- `'nil', never show the jump identifier.
|
|
||||||
- `'prompted', only show it when using centaur-tabs-ace-jump.
|
|
||||||
- `'always', always show it regardless of the status."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type '(choice :tag "show identifier when..."
|
|
||||||
(const :tag "Never" nil)
|
|
||||||
(const :tag "Only when prompted" prompted)
|
|
||||||
(const :tag "Always" always)))
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-ace-jump-dim-buffer t
|
|
||||||
"Whether to dim the current buffer when centaur-ace-jump is activated."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'centaur-tabs)
|
|
||||||
|
|
||||||
(defvar centaur-tabs-ace-jump-keys
|
|
||||||
'(?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)
|
|
||||||
"Buffer jump keys used by centaur-tabs-ace-jump.")
|
|
||||||
|
|
||||||
(defvar centaur-tabs-ace-dispatch-alist
|
|
||||||
'((?q exit "Exit")
|
|
||||||
(?\C-g exit "Exit")
|
|
||||||
(?j jump-to-tab "Jump to tab")
|
|
||||||
(?x close-tab "Close tab")
|
|
||||||
(?s swap-tab "Swap tab")
|
|
||||||
(?\[ backward-group "Previous group")
|
|
||||||
(?\] forward-group "Next group")
|
|
||||||
(?? show-help "Show dispatch help"))
|
|
||||||
"Action keys used by centaur-tabs-ace-jump.
|
|
||||||
The value of each element must be in the form:
|
|
||||||
\(key keyword docstring), where keyword must be one of the follows:
|
|
||||||
\(exit, jump-to-tab, close-tab, swap-tab, backward-group,
|
|
||||||
forward-group, show-help).")
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Close buttons, modified marker and edges' margins
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-set-close-button t
|
|
||||||
"When non nil, display a clickable close button on the right side of the tabs."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-set-left-close-button nil
|
|
||||||
"When non nil, display a clickable close button on the left side of the tabs."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-close-button (make-string 1 #x00D7)
|
|
||||||
"Display appearance of the close buttons, if enabled."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-set-modified-marker nil
|
|
||||||
"When non nil, display a marker when the buffer is modified."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-modified-marker (make-string 1 #x23FA)
|
|
||||||
"Display appearance of the modified marker, if enabled."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-left-edge-margin " "
|
|
||||||
"Text to display at the left edge of the tabs, or nil for no added margin."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-right-edge-margin " "
|
|
||||||
"Text to display at the right edge of the tabs, or nil for no added margin."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Selected tab bar
|
|
||||||
|
|
||||||
(defun centaur-tabs--make-xpm (face width height)
|
|
||||||
"Create an XPM bitmap via FACE WIDTH and HEIGHT.
|
|
||||||
Taken from `doom-modeline'."
|
|
||||||
(when (and (display-graphic-p)
|
|
||||||
(image-type-available-p 'xpm))
|
|
||||||
(propertize
|
|
||||||
" " 'display
|
|
||||||
(let ((data (make-list height (make-list width 1)))
|
|
||||||
(color (or (face-background face nil t) "None")))
|
|
||||||
(ignore-errors
|
|
||||||
(create-image
|
|
||||||
(concat
|
|
||||||
(format
|
|
||||||
"/* XPM */\nstatic char * percent[] = {\n\"%i %i 2 1\",\n\". c %s\",\n\" c %s\","
|
|
||||||
(length (car data)) (length data) color color)
|
|
||||||
(apply #'concat
|
|
||||||
(cl-loop with idx = 0
|
|
||||||
with len = (length data)
|
|
||||||
for dl in data
|
|
||||||
do (cl-incf idx)
|
|
||||||
collect
|
|
||||||
(concat
|
|
||||||
"\""
|
|
||||||
(cl-loop for d in dl
|
|
||||||
if (= d 0) collect (string-to-char " ")
|
|
||||||
else collect (string-to-char "."))
|
|
||||||
(if (eq idx len) "\"};" "\",\n")))))
|
|
||||||
'xpm t :ascent 'center))))))
|
|
||||||
|
|
||||||
(defvar centaur-tabs-active-bar
|
|
||||||
(centaur-tabs--make-xpm 'centaur-tabs-active-bar-face
|
|
||||||
2
|
|
||||||
centaur-tabs-bar-height))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Navigation buttons
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-show-navigation-buttons nil
|
|
||||||
"When non-nil, show the buttons for backward/forward tabs."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-down-tab-text " ▾ "
|
|
||||||
"Text icon to show in the down button tab."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-backward-tab-text " ⏴ "
|
|
||||||
"Text icon to show in the backward button tab."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-forward-tab-text " ⏵ "
|
|
||||||
"Text icon to show in the forward button tab."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-show-count nil
|
|
||||||
"When non-nil, show the current index and count of tabs in the current group."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-count-format " [%d/%d] "
|
|
||||||
"Format text to display count."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; New tab button
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-show-new-tab-button t
|
|
||||||
"When non-nil, show the button to create a new tab."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom centaur-tabs-new-tab-text " + "
|
|
||||||
"Text icon to show in the new-tab button."
|
|
||||||
:group 'centaur-tabs
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Separators
|
|
||||||
|
|
||||||
(defvar centaur-tabs-style-left nil)
|
|
||||||
(defvar centaur-tabs-style-right nil)
|
|
||||||
|
|
||||||
(defvar ns-use-srgb-colorspace)
|
|
||||||
|
|
||||||
(defvar centaur-tabs-image-apple-rgb
|
|
||||||
(and (eq (window-system) 'ns)
|
|
||||||
ns-use-srgb-colorspace
|
|
||||||
(< 11
|
|
||||||
(string-to-number
|
|
||||||
(and (string-match "darwin\\([0-9]+\\)" system-configuration)
|
|
||||||
(match-string-no-properties 1 system-configuration)))))
|
|
||||||
"Boolean variable to determine whether to use Apple RGB colorspace.
|
|
||||||
used to render images.
|
|
||||||
|
|
||||||
t on macOS 10.7+ and `ns-use-srgb-colorspace' is t, nil otherwise.
|
|
||||||
|
|
||||||
This variable is automatically set, there's no need to modify it.")
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-interpolate (color1 color2)
|
|
||||||
"Interpolate between COLOR1 and COLOR2.
|
|
||||||
|
|
||||||
COLOR1 and COLOR2 must be supplied as hex strings with a leading #."
|
|
||||||
(let* ((c1 (color-name-to-rgb color1))
|
|
||||||
(c2 (color-name-to-rgb color2))
|
|
||||||
(red (/ (+ (nth 0 c1) (nth 0 c2)) 2))
|
|
||||||
(green (/ (+ (nth 1 c1) (nth 1 c2)) 2))
|
|
||||||
(blue (/ (+ (nth 2 c1) (nth 2 c2)) 2)))
|
|
||||||
(color-rgb-to-hex red green blue)))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-color-xyz-to-apple-rgb (X Y Z)
|
|
||||||
"Convert CIE X Y Z colors to Apple RGB color space."
|
|
||||||
(let ((r (+ (* 3.2404542 X) (* -1.5371385 Y) (* -0.4985314 Z)))
|
|
||||||
(g (+ (* -0.9692660 X) (* 1.8760108 Y) (* 0.0415560 Z)))
|
|
||||||
(b (+ (* 0.0556434 X) (* -0.2040259 Y) (* 1.0572252 Z))))
|
|
||||||
(list (expt r (/ 1.8)) (expt g (/ 1.8)) (expt b (/ 1.8)))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-color-srgb-to-apple-rgb (red green blue)
|
|
||||||
"Convert RED GREEN BLUE colors from sRGB color space to Apple RGB.
|
|
||||||
RED, GREEN and BLUE should be between 0.0 and 1.0, inclusive."
|
|
||||||
(apply #'centaur-tabs-separator-color-xyz-to-apple-rgb (color-srgb-to-xyz red green blue)))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-hex-color (color)
|
|
||||||
"Get the hexadecimal value of COLOR."
|
|
||||||
(when color
|
|
||||||
(let ((srgb-color (color-name-to-rgb color)))
|
|
||||||
(if centaur-tabs-image-apple-rgb
|
|
||||||
(apply #'color-rgb-to-hex (apply #'centaur-tabs-separator-color-srgb-to-apple-rgb srgb-color))
|
|
||||||
(apply #'color-rgb-to-hex srgb-color)))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-pattern (lst)
|
|
||||||
"Turn LST into an infinite pattern."
|
|
||||||
(when lst
|
|
||||||
(let ((pattern (cl-copy-list lst)))
|
|
||||||
(setcdr (last pattern) pattern))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-pattern-to-string (pattern)
|
|
||||||
"Convert a PATTERN into a string that can be used in an XPM."
|
|
||||||
(concat "\"" (mapconcat #'number-to-string pattern "") "\","))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-reverse-pattern (pattern)
|
|
||||||
"Reverse each line in PATTERN."
|
|
||||||
(mapcar 'reverse pattern))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-row-pattern (fill total &optional fade)
|
|
||||||
"Make a list that has FILL 0s out of TOTAL 1s with FADE 2s to the right of
|
|
||||||
the fill."
|
|
||||||
(unless fade (setq fade 0))
|
|
||||||
(let ((fill (min fill total))
|
|
||||||
(fade (min fade (max (- total fill) 0))))
|
|
||||||
(append (make-list fill 0)
|
|
||||||
(make-list fade 2)
|
|
||||||
(make-list (- total fill fade) 1))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-pattern-bindings-body (patterns height-exp pattern-height-sym
|
|
||||||
second-pattern-height-sym)
|
|
||||||
"Create let-var bindings and a function body from PATTERNS.
|
|
||||||
The `car' and `cdr' parts of the result can be passed to the
|
|
||||||
function `centaur-tabs-separator-wrap-defun' as its `let-vars'
|
|
||||||
and `body' arguments,respectively. HEIGHT-EXP is an expression
|
|
||||||
calculating the image height and it should contain a free variable `height'.
|
|
||||||
PATTERN-HEIGHT-SYM and SECOND-PATTERN-HEIGHT-SYM are symbols used
|
|
||||||
for let-var binding variables."
|
|
||||||
(let* ((pattern (centaur-tabs-separator-pattern (mapcar 'centaur-tabs-separator-pattern-to-string (car patterns))))
|
|
||||||
(header (mapcar 'centaur-tabs-separator-pattern-to-string (nth 1 patterns)))
|
|
||||||
(footer (mapcar 'centaur-tabs-separator-pattern-to-string (nth 2 patterns)))
|
|
||||||
(second-pattern (centaur-tabs-separator-pattern (mapcar 'centaur-tabs-separator-pattern-to-string (nth 3 patterns))))
|
|
||||||
(center (mapcar 'centaur-tabs-separator-pattern-to-string (nth 4 patterns)))
|
|
||||||
(reserve (+ (length header) (length footer) (length center))))
|
|
||||||
(when pattern
|
|
||||||
(cons `((,pattern-height-sym (max (- ,height-exp ,reserve) 0))
|
|
||||||
(,second-pattern-height-sym (/ ,pattern-height-sym 2))
|
|
||||||
(,pattern-height-sym ,(if second-pattern `(ceiling ,pattern-height-sym 2) `,pattern-height-sym)))
|
|
||||||
(list (when header `(mapconcat 'identity ',header ""))
|
|
||||||
`(mapconcat 'identity
|
|
||||||
(cl-subseq ',pattern 0 ,pattern-height-sym) "")
|
|
||||||
(when center `(mapconcat 'identity ',center ""))
|
|
||||||
(when second-pattern
|
|
||||||
`(mapconcat 'identity
|
|
||||||
(cl-subseq ',second-pattern
|
|
||||||
0 ,second-pattern-height-sym) ""))
|
|
||||||
(when footer `(mapconcat 'identity ',footer "")))))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-pattern-defun (name dir width &rest patterns)
|
|
||||||
"Create a powerline function of NAME in DIR with WIDTH for PATTERNS.
|
|
||||||
|
|
||||||
PATTERNS is of the form (PATTERN HEADER FOOTER SECOND-PATTERN CENTER
|
|
||||||
PATTERN-2X HEADER-2X FOOTER-2X SECOND-PATTERN-2X CENTER-2X).
|
|
||||||
PATTERN is required, all other components are optional.
|
|
||||||
The first 5 components are for the standard resolution image.
|
|
||||||
The remaining ones are for the high resolution image where both
|
|
||||||
width and height are doubled. If PATTERN-2X is nil or not given,
|
|
||||||
then the remaining components are ignored and the standard
|
|
||||||
resolution image with magnification and interpolation will be
|
|
||||||
used in high resolution environments
|
|
||||||
|
|
||||||
All generated functions generate the form:
|
|
||||||
HEADER
|
|
||||||
PATTERN ...
|
|
||||||
CENTER
|
|
||||||
SECOND-PATTERN ...
|
|
||||||
FOOTER
|
|
||||||
|
|
||||||
PATTERN and SECOND-PATTERN repeat infinitely to fill the space needed to
|
|
||||||
generate a full height XPM.
|
|
||||||
|
|
||||||
PATTERN, HEADER, FOOTER, SECOND-PATTERN, CENTER are of the form
|
|
||||||
\((COLOR ...) (COLOR ...) ...).
|
|
||||||
|
|
||||||
COLOR can be one of 0, 1, or 2, where 0 is the source color, 1 is the
|
|
||||||
destination color, and 2 is the interpolated color between 0 and 1."
|
|
||||||
(when (eq dir 'right)
|
|
||||||
(setq patterns (mapcar 'centaur-tabs-separator-reverse-pattern patterns)))
|
|
||||||
(let ((bindings-body (centaur-tabs-separator-pattern-bindings-body patterns
|
|
||||||
'height
|
|
||||||
'pattern-height
|
|
||||||
'second-pattern-height))
|
|
||||||
(bindings-body-2x (centaur-tabs-separator-pattern-bindings-body (nthcdr 5 patterns)
|
|
||||||
'(* height 2)
|
|
||||||
'pattern-height-2x
|
|
||||||
'second-pattern-height-2x)))
|
|
||||||
(centaur-tabs-separator-wrap-defun name dir width
|
|
||||||
(append (car bindings-body) (car bindings-body-2x))
|
|
||||||
(cdr bindings-body) (cdr bindings-body-2x))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-background-color (face)
|
|
||||||
"Set the separator background color using FACE."
|
|
||||||
(face-attribute face
|
|
||||||
(if (face-attribute face :inverse-video nil 'default)
|
|
||||||
:foreground
|
|
||||||
:background)
|
|
||||||
nil
|
|
||||||
'default))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-wrap-defun (name dir width let-vars body &optional body-2x)
|
|
||||||
"Generate a powerline function of name NAME in dir DIR.
|
|
||||||
This is made with WIDTH using LET-VARS and BODY.
|
|
||||||
BODY-2X is an optional argument."
|
|
||||||
(let* ((src-face (if (eq dir 'left) 'face1 'face2))
|
|
||||||
(dst-face (if (eq dir 'left) 'face2 'face1)))
|
|
||||||
`(defun ,(intern (format "powerline-%s-%s" name (symbol-name dir)))
|
|
||||||
(face1 face2 &optional height)
|
|
||||||
(when window-system
|
|
||||||
(unless height (setq height centaur-tabs-height))
|
|
||||||
(let* ,(append `((color1 (when ,src-face
|
|
||||||
(centaur-tabs-separator-hex-color (centaur-tabs-separator-background-color ,src-face))))
|
|
||||||
(color2 (when ,dst-face
|
|
||||||
(centaur-tabs-separator-hex-color (centaur-tabs-separator-background-color ,dst-face))))
|
|
||||||
(colori (when (and color1 color2) (centaur-tabs-separator-interpolate color1 color2)))
|
|
||||||
(color1 (or color1 "None"))
|
|
||||||
(color2 (or color2 "None"))
|
|
||||||
(colori (or colori "None")))
|
|
||||||
let-vars)
|
|
||||||
(apply #'create-image
|
|
||||||
,(append `(concat (format "/* XPM */ static char * %s_%s[] = { \"%s %s 3 1\", \"0 c %s\", \"1 c %s\", \"2 c %s\","
|
|
||||||
,(replace-regexp-in-string "-" "_" name)
|
|
||||||
(symbol-name ',dir)
|
|
||||||
,width
|
|
||||||
height
|
|
||||||
color1
|
|
||||||
color2
|
|
||||||
colori))
|
|
||||||
body
|
|
||||||
'("};"))
|
|
||||||
'xpm t
|
|
||||||
:ascent 'center
|
|
||||||
:face (when (and face1 face2)
|
|
||||||
,dst-face)
|
|
||||||
,(and body-2x
|
|
||||||
`(and (featurep 'mac)
|
|
||||||
(list :data-2x
|
|
||||||
,(append `(concat (format "/* XPM */ static char * %s_%s_2x[] = { \"%s %s 3 1\", \"0 c %s\", \"1 c %s\", \"2 c %s\","
|
|
||||||
,(replace-regexp-in-string "-" "_" name)
|
|
||||||
(symbol-name ',dir)
|
|
||||||
(* ,width 2)
|
|
||||||
(* height 2)
|
|
||||||
color1
|
|
||||||
color2
|
|
||||||
colori))
|
|
||||||
body-2x
|
|
||||||
'("};")))))))))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-alternate (dir)
|
|
||||||
"Generate an alternating pattern XPM function for DIR."
|
|
||||||
(centaur-tabs-separator-pattern-defun "alternate" dir 4
|
|
||||||
'((2 2 1 1)
|
|
||||||
(0 0 2 2))
|
|
||||||
nil nil nil nil
|
|
||||||
;; 2x
|
|
||||||
'((2 2 2 2 1 1 1 1)
|
|
||||||
(2 2 2 2 1 1 1 1)
|
|
||||||
(0 0 0 0 2 2 2 2)
|
|
||||||
(0 0 0 0 2 2 2 2))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-bar (dir)
|
|
||||||
"Generate a bar XPM function for DIR."
|
|
||||||
(centaur-tabs-separator-pattern-defun "bar" dir 2
|
|
||||||
'((2 2))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-box (dir)
|
|
||||||
"Generate a box XPM function for DIR."
|
|
||||||
(centaur-tabs-separator-pattern-defun "box" dir 2
|
|
||||||
'((0 0)
|
|
||||||
(0 0)
|
|
||||||
(1 1)
|
|
||||||
(1 1))
|
|
||||||
nil nil nil nil
|
|
||||||
;; 2x
|
|
||||||
'((0 0 0 0)
|
|
||||||
(0 0 0 0)
|
|
||||||
(0 0 0 0)
|
|
||||||
(0 0 0 0)
|
|
||||||
(1 1 1 1)
|
|
||||||
(1 1 1 1)
|
|
||||||
(1 1 1 1)
|
|
||||||
(1 1 1 1))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-chamfer (dir)
|
|
||||||
"Generate a chamfer XPM function for DIR."
|
|
||||||
(centaur-tabs-separator-pattern-defun "chamfer" dir 3
|
|
||||||
'((0 0 0))
|
|
||||||
'((1 1 1)
|
|
||||||
(0 1 1)
|
|
||||||
(0 0 1))
|
|
||||||
nil nil nil
|
|
||||||
;; 2x
|
|
||||||
'((0 0 0 0 0 0))
|
|
||||||
'((1 1 1 1 1 1)
|
|
||||||
(0 1 1 1 1 1)
|
|
||||||
(0 0 1 1 1 1)
|
|
||||||
(0 0 0 1 1 1)
|
|
||||||
(0 0 0 0 1 1)
|
|
||||||
(0 0 0 0 0 1))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-rounded (dir)
|
|
||||||
"Generate a rounded XPM function for DIR."
|
|
||||||
(centaur-tabs-separator-pattern-defun "rounded" dir 6
|
|
||||||
'((0 0 0 0 0 0))
|
|
||||||
'((2 1 1 1 1 1)
|
|
||||||
(0 0 2 1 1 1)
|
|
||||||
(0 0 0 0 1 1)
|
|
||||||
(0 0 0 0 2 1)
|
|
||||||
(0 0 0 0 0 1)
|
|
||||||
(0 0 0 0 0 2))
|
|
||||||
nil nil nil
|
|
||||||
;; 2x
|
|
||||||
'((0 0 0 0 0 0 0 0 0 0 0 0))
|
|
||||||
'((1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 2 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 2 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 2 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 1))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-slant (dir)
|
|
||||||
"Generate a slant XPM function for DIR."
|
|
||||||
(let* ((row-modifier (if (eq dir 'left) 'identity 'reverse)))
|
|
||||||
(centaur-tabs-separator-wrap-defun "slant" dir 'width
|
|
||||||
'((width (1- (ceiling height 2))))
|
|
||||||
`((cl-loop for i from 0 to (1- height)
|
|
||||||
concat (centaur-tabs-separator-pattern-to-string (,row-modifier (centaur-tabs-separator-row-pattern (/ i 2) width)))))
|
|
||||||
`((cl-loop for i from 0 to (1- (* height 2))
|
|
||||||
concat (centaur-tabs-separator-pattern-to-string (,row-modifier (centaur-tabs-separator-row-pattern (/ i 2) (* width 2)))))))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-wave (dir)
|
|
||||||
"Generate a wave XPM function for DIR."
|
|
||||||
(centaur-tabs-separator-pattern-defun "wave" dir 11
|
|
||||||
'((0 0 0 0 0 0 1 1 1 1 1))
|
|
||||||
'((2 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 2 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 2 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 2 1 1 1 1 1))
|
|
||||||
'((0 0 0 0 0 0 2 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 2 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 2 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 2))
|
|
||||||
nil nil
|
|
||||||
;; 2x
|
|
||||||
'((0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1))
|
|
||||||
'((1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1))
|
|
||||||
'((0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1)
|
|
||||||
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-zigzag (dir)
|
|
||||||
"Generate a zigzag pattern XPM function for DIR."
|
|
||||||
(centaur-tabs-separator-pattern-defun "zigzag" dir 3
|
|
||||||
'((1 1 1)
|
|
||||||
(0 1 1)
|
|
||||||
(0 0 1)
|
|
||||||
(0 0 0)
|
|
||||||
(0 0 1)
|
|
||||||
(0 1 1))
|
|
||||||
nil nil nil nil
|
|
||||||
;; 2x
|
|
||||||
'((1 1 1 1 1 1)
|
|
||||||
(0 1 1 1 1 1)
|
|
||||||
(0 0 1 1 1 1)
|
|
||||||
(0 0 0 1 1 1)
|
|
||||||
(0 0 0 0 1 1)
|
|
||||||
(0 0 0 0 0 1)
|
|
||||||
(0 0 0 0 0 0)
|
|
||||||
(0 0 0 0 0 1)
|
|
||||||
(0 0 0 0 1 1)
|
|
||||||
(0 0 0 1 1 1)
|
|
||||||
(0 0 1 1 1 1)
|
|
||||||
(0 1 1 1 1 1))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-memoize (func)
|
|
||||||
"Memoize FUNC.
|
|
||||||
If argument is a symbol then install the memoized function over
|
|
||||||
the original function. Use frame-local memoization."
|
|
||||||
(cl-typecase func
|
|
||||||
(symbol (fset func (centaur-tabs-separator-memoize-wrap-frame-local (symbol-function func))) func)
|
|
||||||
(function (centaur-tabs-separator-memoize-wrap-frame-local func))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-memoize-wrap-frame-local (func)
|
|
||||||
"Return the memoized version of FUNC.
|
|
||||||
The memoization cache is frame-local."
|
|
||||||
(let ((funcid (cl-gensym)))
|
|
||||||
`(lambda (&rest args)
|
|
||||||
,(concat (documentation func) (format "\n(memoized function %s)" funcid))
|
|
||||||
(let* ((cache (centaur-tabs-separator-create-or-get-cache))
|
|
||||||
(key (cons ',funcid args))
|
|
||||||
(val (gethash key cache)))
|
|
||||||
(or val
|
|
||||||
(puthash key (apply ,func args) cache))))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-create-or-get-cache ()
|
|
||||||
"Return a frame-local hash table that acts as a memoization cache.
|
|
||||||
The cache is for the powerline.
|
|
||||||
Create one if the frame doesn't have one yet."
|
|
||||||
(if-let* ((table (frame-parameter nil 'powerline-cache))
|
|
||||||
((hash-table-p table)))
|
|
||||||
table
|
|
||||||
(centaur-tabs-separator-reset-cache)))
|
|
||||||
|
|
||||||
(defun centaur-tabs-separator-reset-cache ()
|
|
||||||
"Reset and return the frame-local hash table used for a memoization cache."
|
|
||||||
(let ((table (make-hash-table :test 'equal)))
|
|
||||||
;; Store it as a frame-local variable
|
|
||||||
(modify-frame-parameters nil `((powerline-cache . ,table)))
|
|
||||||
table))
|
|
||||||
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-alternate 'left))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-alternate 'right))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-bar 'left))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-bar 'right))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-box 'left))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-box 'right))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-chamfer 'left))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-chamfer 'right))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-rounded 'left))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-rounded 'right))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-slant 'left))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-slant 'right))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-wave 'left))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-wave 'right))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-zigzag 'left))
|
|
||||||
(centaur-tabs-separator-memoize (centaur-tabs-separator-zigzag 'right))
|
|
||||||
|
|
||||||
(defun centaur-tabs-select-separator-style (tab-style)
|
|
||||||
"Set the separator style to TAB-STYLE."
|
|
||||||
(let* ((theme (or (car custom-enabled-themes) "default"))
|
|
||||||
(name (intern (format "centaur-tabs--%s-%s-face" theme tab-style)))
|
|
||||||
(face (copy-face 'centaur-tabs-default name)))
|
|
||||||
(setq centaur-tabs-style-left
|
|
||||||
(funcall (intern (format "powerline-%s-right" tab-style))
|
|
||||||
face nil centaur-tabs-height))
|
|
||||||
(setq centaur-tabs-style-right
|
|
||||||
(funcall (intern (format "powerline-%s-left" tab-style))
|
|
||||||
nil face centaur-tabs-height))))
|
|
||||||
|
|
||||||
(provide 'centaur-tabs-elements)
|
|
||||||
;;; centaur-tabs-elements.el ends here
|
|
|
@ -1,642 +0,0 @@
|
||||||
;;; centaur-tabs-interactive.el --- centaur-tabs interactive functions and plugins support lexical-binding: t; -*-
|
|
||||||
|
|
||||||
;; Copyright (C) 2019-2024 Emmanuel Bustos
|
|
||||||
;; Copyright (C) 2024 Jen-Chieh Shen
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or
|
|
||||||
;; modify it under the terms of the GNU General Public License as
|
|
||||||
;; published by the Free Software Foundation; either version 2, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
;;
|
|
||||||
;; This program is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
;; General Public License for more details.
|
|
||||||
;;
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with this program; see the file COPYING. If not, write to
|
|
||||||
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
||||||
;; Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
;;
|
|
||||||
;; This file contains centaur-tabs interactive functions and plugins support
|
|
||||||
;;
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'centaur-tabs-elements)
|
|
||||||
|
|
||||||
;; Compiler pacifier
|
|
||||||
(declare-function ivy-read "ext:ivy.el" t t)
|
|
||||||
(declare-function helm-build-sync-source "ext:helm-source.el" t t)
|
|
||||||
(defvar helm-source-centaur-tabs-group)
|
|
||||||
(declare-function projectile-project-root "ext:projectile.el" t t)
|
|
||||||
(declare-function projectile-project-name "ext:projectile.el" t t)
|
|
||||||
|
|
||||||
(declare-function centaur-tabs-do-select "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-tab-from-event "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-tab-value "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-tabset "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-buffer-show-groups "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-buffer-close-tab "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-view "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-extensions "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-selected-tab "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-display-update "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-set-template "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-buffer-select-tab "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-tabs "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-tab-tabset "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-tabsets-tabset "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-current-tabset "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-completing-read "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-get-groups "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-forward-group "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-backward-group "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-forward-tab "centaur-tabs-functions.el")
|
|
||||||
(declare-function centaur-tabs-backward-tab "centaur-tabs-functions.el")
|
|
||||||
|
|
||||||
(defvar centaur-tabs-cycle-scope)
|
|
||||||
(defvar centaur-tabs-current-tabset)
|
|
||||||
(defvar centaur-tabs-last-focused-buffer-group)
|
|
||||||
(defvar centaur-tabs-buffer-list-function)
|
|
||||||
(defvar centaur-tabs-buffer-groups-function)
|
|
||||||
(defvar centaur-tabs--buffer-show-groups)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;; Interactive functions ;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(defun centaur-tabs-switch-group (&optional groupname)
|
|
||||||
"Switch tab groups using ido. GROUPNAME can optionaly be provided."
|
|
||||||
(interactive)
|
|
||||||
(let* ((tab-buffer-list (mapcar
|
|
||||||
#'(lambda (b)
|
|
||||||
(with-current-buffer b
|
|
||||||
(list (current-buffer)
|
|
||||||
(buffer-name)
|
|
||||||
(funcall centaur-tabs-buffer-groups-function) )))
|
|
||||||
(funcall centaur-tabs-buffer-list-function)))
|
|
||||||
(groups (centaur-tabs-get-groups))
|
|
||||||
(group-name (or groupname (centaur-tabs-completing-read "Groups: " groups))) )
|
|
||||||
(catch 'done
|
|
||||||
(mapc #'(lambda (group)
|
|
||||||
(when (equal group-name (car (car (cdr (cdr group)))))
|
|
||||||
(throw 'done (switch-to-buffer (car (cdr group))))))
|
|
||||||
tab-buffer-list) )))
|
|
||||||
|
|
||||||
(defun centaur-tabs-select-end-tab ()
|
|
||||||
"Select end tab of current tabset."
|
|
||||||
(interactive)
|
|
||||||
(centaur-tabs-select-beg-tab t))
|
|
||||||
|
|
||||||
(defun centaur-tabs-select-beg-tab (&optional backward)
|
|
||||||
"Select beginning tab of current tabs.
|
|
||||||
If BACKWARD is non-nil, move backward, otherwise move forward.
|
|
||||||
TYPE is default option."
|
|
||||||
(interactive)
|
|
||||||
(let* ((tabset (centaur-tabs-current-tabset t))
|
|
||||||
(ttabset (centaur-tabs-get-tabsets-tabset))
|
|
||||||
(_cycle (if (and (eq centaur-tabs-cycle-scope 'groups)
|
|
||||||
(not (cdr (centaur-tabs-tabs ttabset))))
|
|
||||||
'tabs
|
|
||||||
centaur-tabs-cycle-scope))
|
|
||||||
_selected tab)
|
|
||||||
(when tabset
|
|
||||||
(setq tabset (centaur-tabs-tabs tabset)
|
|
||||||
tab (car (if backward (last tabset) tabset)))
|
|
||||||
(centaur-tabs-buffer-select-tab tab))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-backward-tab-other-window (&optional reversed)
|
|
||||||
"Move to left tab in other window.
|
|
||||||
Optional argument REVERSED default is move backward, if reversed is non-nil
|
|
||||||
move forward."
|
|
||||||
(interactive)
|
|
||||||
(other-window 1)
|
|
||||||
(if reversed
|
|
||||||
(centaur-tabs-forward-tab)
|
|
||||||
(centaur-tabs-backward-tab))
|
|
||||||
(other-window -1))
|
|
||||||
|
|
||||||
(defun centaur-tabs-forward-tab-other-window ()
|
|
||||||
"Move to right tab in other window."
|
|
||||||
(interactive)
|
|
||||||
(centaur-tabs-backward-tab-other-window t))
|
|
||||||
|
|
||||||
(defun centaur-tabs-move-current-tab-to-right ()
|
|
||||||
"Move current tab one place right, unless it's already the rightmost."
|
|
||||||
(interactive)
|
|
||||||
(let* ((bufset (centaur-tabs-current-tabset t))
|
|
||||||
(old-bufs (centaur-tabs-tabs bufset))
|
|
||||||
(new-bufs (list))
|
|
||||||
the-buffer)
|
|
||||||
(while (and
|
|
||||||
old-bufs
|
|
||||||
(not (string= (buffer-name) (format "%s" (car (car old-bufs))))))
|
|
||||||
(push (car old-bufs) new-bufs)
|
|
||||||
(setq old-bufs (cdr old-bufs)))
|
|
||||||
(if old-bufs ; if this is false, then the current tab's buffer name is mysteriously missing
|
|
||||||
(progn
|
|
||||||
(setq the-buffer (car old-bufs))
|
|
||||||
(setq old-bufs (cdr old-bufs))
|
|
||||||
(if old-bufs ; if this is false, then the current tab is the rightmost
|
|
||||||
(push (car old-bufs) new-bufs))
|
|
||||||
(push the-buffer new-bufs)) ; this is the tab that was to be moved
|
|
||||||
(error "Error: current buffer's name was not found in Centaur-Tabs's buffer list"))
|
|
||||||
(setq new-bufs (reverse new-bufs))
|
|
||||||
(setq new-bufs (append new-bufs (cdr old-bufs)))
|
|
||||||
(set bufset new-bufs)
|
|
||||||
(centaur-tabs-set-template bufset nil)
|
|
||||||
(centaur-tabs-display-update)))
|
|
||||||
|
|
||||||
(defun centaur-tabs-move-current-tab-to-left ()
|
|
||||||
"Move current tab one place left, unless it's already the leftmost."
|
|
||||||
(interactive)
|
|
||||||
(let* ((bufset (centaur-tabs-current-tabset t))
|
|
||||||
(old-bufs (centaur-tabs-tabs bufset))
|
|
||||||
(first-buf (car old-bufs))
|
|
||||||
(new-bufs (list))
|
|
||||||
not-yet-this-buf)
|
|
||||||
(if (string= (buffer-name) (format "%s" (car first-buf)))
|
|
||||||
old-bufs ; the current tab is the leftmost
|
|
||||||
(setq not-yet-this-buf first-buf)
|
|
||||||
(setq old-bufs (cdr old-bufs))
|
|
||||||
(while (and
|
|
||||||
old-bufs
|
|
||||||
(not (string= (buffer-name) (format "%s" (car (car old-bufs))))))
|
|
||||||
(push not-yet-this-buf new-bufs)
|
|
||||||
(setq not-yet-this-buf (car old-bufs))
|
|
||||||
(setq old-bufs (cdr old-bufs)))
|
|
||||||
(if old-bufs ; if this is false, then the current tab's buffer name is mysteriously missing
|
|
||||||
(progn
|
|
||||||
(push (car old-bufs) new-bufs) ; this is the tab that was to be moved
|
|
||||||
(push not-yet-this-buf new-bufs)
|
|
||||||
(setq new-bufs (reverse new-bufs))
|
|
||||||
(setq new-bufs (append new-bufs (cdr old-bufs))))
|
|
||||||
(error "Error: current buffer's name was not found in Centaur-Tabs's buffer list"))
|
|
||||||
(set bufset new-bufs)
|
|
||||||
(centaur-tabs-set-template bufset nil)
|
|
||||||
(centaur-tabs-display-update))))
|
|
||||||
|
|
||||||
(defmacro centaur-tabs-kill-buffer-match-rule (match-rule)
|
|
||||||
"If buffer match MATCH-RULE, kill it."
|
|
||||||
`(save-excursion
|
|
||||||
(mapc #'(lambda (buffer)
|
|
||||||
(with-current-buffer buffer
|
|
||||||
(when (string-equal current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
|
||||||
(when (funcall ,match-rule buffer)
|
|
||||||
(kill-buffer buffer)))))
|
|
||||||
(buffer-list))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-kill-all-buffers-in-current-group ()
|
|
||||||
"Kill all buffers in current group."
|
|
||||||
(interactive)
|
|
||||||
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t)))))
|
|
||||||
;; Kill all buffers in current group.
|
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
|
||||||
(lambda (_buffer) t))
|
|
||||||
;; Switch to next group.
|
|
||||||
(centaur-tabs-forward-group)))
|
|
||||||
|
|
||||||
(defun centaur-tabs-kill-other-buffers-in-current-group ()
|
|
||||||
"Kill all buffers except current buffer in current group."
|
|
||||||
(interactive)
|
|
||||||
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
|
||||||
(currentbuffer (current-buffer)))
|
|
||||||
;; Kill all buffers in current group.
|
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
|
||||||
(lambda (buffer) (not (equal buffer currentbuffer))))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-kill-unmodified-buffers-in-current-group ()
|
|
||||||
"Kill all unmodified buffer in current group."
|
|
||||||
(interactive)
|
|
||||||
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
|
||||||
(currentbuffer (current-buffer)))
|
|
||||||
;; Kill all buffers in current group.
|
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
|
||||||
(lambda (buffer) (not (buffer-modified-p buffer))))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-kill-match-buffers-in-current-group ()
|
|
||||||
"Kill all buffers match extension in current group."
|
|
||||||
(interactive)
|
|
||||||
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
|
||||||
(extension-names (centaur-tabs-get-extensions))
|
|
||||||
match-extension)
|
|
||||||
;; Read extension need to kill.
|
|
||||||
(setq match-extension (centaur-tabs-completing-read "Kill buffers suffix with: " extension-names))
|
|
||||||
;; Kill all buffers match extension in current group.
|
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
|
||||||
(lambda (buffer)
|
|
||||||
(let ((filename (buffer-file-name buffer)))
|
|
||||||
(and filename (string-equal (file-name-extension filename) match-extension)))))
|
|
||||||
;; Switch to next group if last file killed.
|
|
||||||
(when (equal (length extension-names) 1)
|
|
||||||
(centaur-tabs-forward-group))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-keep-match-buffers-in-current-group ()
|
|
||||||
"Keep all buffers match extension in current group."
|
|
||||||
(interactive)
|
|
||||||
(let* ((current-group-name (cdr (centaur-tabs-selected-tab (centaur-tabs-current-tabset t))))
|
|
||||||
(extension-names (centaur-tabs-get-extensions))
|
|
||||||
match-extension)
|
|
||||||
;; Read extension need to kill.
|
|
||||||
(setq match-extension (centaur-tabs-completing-read "Just keep buffers suffix with: " extension-names))
|
|
||||||
;; Kill all buffers match extension in current group.
|
|
||||||
(centaur-tabs-kill-buffer-match-rule
|
|
||||||
(lambda (buffer)
|
|
||||||
(let ((filename (buffer-file-name buffer)))
|
|
||||||
(and filename (not (string-equal (file-name-extension filename) match-extension))))))
|
|
||||||
;; Switch to next group if last file killed.
|
|
||||||
(when (equal (length extension-names) 1)
|
|
||||||
(centaur-tabs-forward-group))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-select-visible-nth-tab (tab-index)
|
|
||||||
"Select visible tab with TAB-INDEX'.
|
|
||||||
Example, when `tab-index' is 1, this function will select the leftmost label in
|
|
||||||
the visible area, instead of the first label in the current group.
|
|
||||||
If `tab-index' more than length of visible tabs, selet the last tab.
|
|
||||||
|
|
||||||
If `tab-index' is 0, select last tab."
|
|
||||||
(let ((visible-tabs (centaur-tabs-view centaur-tabs-current-tabset)))
|
|
||||||
(switch-to-buffer
|
|
||||||
(car
|
|
||||||
(if (or (equal tab-index 0)
|
|
||||||
(> tab-index (length visible-tabs)))
|
|
||||||
(car (last visible-tabs))
|
|
||||||
(nth (- tab-index 1) visible-tabs))))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-select-visible-tab ()
|
|
||||||
"Bind this function with number keystroke, such as s-1, s-2, s-3 ... etc.
|
|
||||||
|
|
||||||
This function automatically recognizes the number at the end of the keystroke
|
|
||||||
and switches to the tab of the corresponding index.
|
|
||||||
|
|
||||||
Note that this function switches to the visible range,
|
|
||||||
not the actual logical index position of the current group."
|
|
||||||
(interactive)
|
|
||||||
(let* ((event last-command-event)
|
|
||||||
(key (make-vector 1 event))
|
|
||||||
(key-desc (key-description key)))
|
|
||||||
(centaur-tabs-select-visible-nth-tab
|
|
||||||
(string-to-number (car (last (split-string key-desc "-")))))))
|
|
||||||
|
|
||||||
;; ace-jump style tab switching
|
|
||||||
|
|
||||||
(defvar centaur-tabs-ace-jump-active nil
|
|
||||||
"Set to t if `centaur-tabs-ace-jump' is invoked.")
|
|
||||||
|
|
||||||
(defvar centaur-tabs-dim-overlay nil
|
|
||||||
"Holds the overlay for dimming buffer when invoking centaur-tabs-ace-jump.")
|
|
||||||
|
|
||||||
(defun centaur-tabs--dim-window ()
|
|
||||||
"Create a dim background overlay for the current window."
|
|
||||||
(when centaur-tabs-ace-jump-dim-buffer
|
|
||||||
(when centaur-tabs-dim-overlay
|
|
||||||
(delete-overlay centaur-tabs-dim-overlay))
|
|
||||||
(setq centaur-tabs-dim-overlay
|
|
||||||
(let ((ol (make-overlay (window-start) (window-end))))
|
|
||||||
(overlay-put ol 'face 'centaur-tabs-dim-buffer-face)
|
|
||||||
ol))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-swap-tab (tab)
|
|
||||||
"Swap the position of current tab with TAB.
|
|
||||||
TAB has to be in the same group as the current tab."
|
|
||||||
(if (eq (centaur-tabs-tab-tabset tab) (centaur-tabs-current-tabset t))
|
|
||||||
(let* ((group (centaur-tabs-current-tabset t))
|
|
||||||
(tabs (cl-copy-list (centaur-tabs-tabs group)))
|
|
||||||
(current (centaur-tabs-selected-tab group))
|
|
||||||
(current-index (cl-position current tabs))
|
|
||||||
(target-index (cl-position tab tabs)))
|
|
||||||
(if (eq tab current)
|
|
||||||
(message "Can't swap with current tab itself.")
|
|
||||||
(setcar (nthcdr current-index tabs) tab)
|
|
||||||
(setcar (nthcdr target-index tabs) current)
|
|
||||||
(set group tabs)
|
|
||||||
(centaur-tabs-set-template (centaur-tabs-current-tabset t) nil)
|
|
||||||
(centaur-tabs-display-update)))
|
|
||||||
(message "Error: %s is not in the same group as the current tab." tab)))
|
|
||||||
|
|
||||||
(defun centaur-tabs-ace-action (action)
|
|
||||||
"Preform ACTION on a visible tab. Ace-jump style.
|
|
||||||
ACTION has to be one of value in `centaur-tabs-ace-dispatch-alist'"
|
|
||||||
(when (centaur-tabs-current-tabset t)
|
|
||||||
(when centaur-tabs-ace-jump-dim-buffer
|
|
||||||
(centaur-tabs--dim-window))
|
|
||||||
(cond ((eq action 'jump-to-tab)
|
|
||||||
(message "Jump to tab: "))
|
|
||||||
((eq action 'close-tab)
|
|
||||||
(message "Close tab: "))
|
|
||||||
((eq action 'swap-tab)
|
|
||||||
(message "Swap current tab with: ")))
|
|
||||||
|
|
||||||
(let ((centaur-tabs-ace-jump-active t))
|
|
||||||
(catch 'done
|
|
||||||
(while t
|
|
||||||
(centaur-tabs-set-template (centaur-tabs-current-tabset t) nil)
|
|
||||||
(centaur-tabs-display-update)
|
|
||||||
(let ((char (read-key)) (action-cache))
|
|
||||||
(cond
|
|
||||||
;; tab keys
|
|
||||||
((memq char centaur-tabs-ace-jump-keys)
|
|
||||||
(let ((sel (nth (cl-position char centaur-tabs-ace-jump-keys) (centaur-tabs-view (centaur-tabs-current-tabset t)))))
|
|
||||||
(cond ((eq sel nil)
|
|
||||||
(message "Tab %s does not exist" (key-description (vector char))))
|
|
||||||
((eq action 'jump-to-tab)
|
|
||||||
(centaur-tabs-buffer-select-tab sel))
|
|
||||||
((eq action 'close-tab)
|
|
||||||
(centaur-tabs-buffer-close-tab sel))
|
|
||||||
((eq action 'swap-tab)
|
|
||||||
(centaur-tabs-swap-tab sel))))
|
|
||||||
(throw 'done nil))
|
|
||||||
;; actions
|
|
||||||
((setq action-cache (assoc char centaur-tabs-ace-dispatch-alist))
|
|
||||||
(setq action-cache (cadr action-cache))
|
|
||||||
(cond ((eq action-cache 'exit) ; exit
|
|
||||||
(message "Quit")
|
|
||||||
(throw 'done nil))
|
|
||||||
((eq action-cache 'forward-group) ; forward group
|
|
||||||
(message "Forward group")
|
|
||||||
(centaur-tabs-forward-group)
|
|
||||||
(centaur-tabs--dim-window))
|
|
||||||
((eq action-cache 'backward-group) ; backward group
|
|
||||||
(message "Backward group")
|
|
||||||
(centaur-tabs-backward-group)
|
|
||||||
(centaur-tabs--dim-window))
|
|
||||||
((eq action-cache 'show-help) ; help menu
|
|
||||||
(message "%s" (mapconcat
|
|
||||||
(lambda (elem) (format "%s: %s"
|
|
||||||
(key-description (vector (car elem)))
|
|
||||||
(caddr elem)))
|
|
||||||
centaur-tabs-ace-dispatch-alist
|
|
||||||
"\n")))
|
|
||||||
(t (setq action action-cache) ; other actions
|
|
||||||
(cond ((eq action-cache 'jump-to-tab)
|
|
||||||
(message "Jump to tab: "))
|
|
||||||
((eq action-cache 'close-tab)
|
|
||||||
(message "Close tab: "))
|
|
||||||
((eq action-cache 'swap-tab)
|
|
||||||
(message "Swap current tab with: "))))))
|
|
||||||
;; no match, repeat
|
|
||||||
(t
|
|
||||||
(message "No such candidate: %s, hit ? for help." (key-description (vector char)))))))))
|
|
||||||
(centaur-tabs-set-template (centaur-tabs-current-tabset t) nil)
|
|
||||||
(when centaur-tabs-ace-jump-dim-buffer
|
|
||||||
(delete-overlay centaur-tabs-dim-overlay)
|
|
||||||
(setq centaur-tabs-dim-overlay nil))
|
|
||||||
(centaur-tabs-display-update)))
|
|
||||||
|
|
||||||
(defun centaur-tabs-ace-jump (&optional arg)
|
|
||||||
"Select a tab and perform an action. Ace-jump style.
|
|
||||||
If no ARG is provided, select that tab. If prefixed with one
|
|
||||||
`universal-argument', swap the current tab with the selected tab.
|
|
||||||
If prefixed with two `universal-argument's, close selected tab."
|
|
||||||
(interactive "p")
|
|
||||||
(cond ((eq arg 1)
|
|
||||||
(centaur-tabs-ace-action 'jump-to-tab))
|
|
||||||
((eq arg 4)
|
|
||||||
(centaur-tabs-ace-action 'swap-tab))
|
|
||||||
((eq arg 16)
|
|
||||||
(centaur-tabs-ace-action 'close-tab))
|
|
||||||
(t
|
|
||||||
(centaur-tabs-ace-action 'jump-to-tab))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-group-buffer-groups ()
|
|
||||||
"Use centaur-tabs's own buffer grouping function."
|
|
||||||
(interactive)
|
|
||||||
(setq centaur-tabs-buffer-groups-function 'centaur-tabs-buffer-groups)
|
|
||||||
(centaur-tabs-display-update))
|
|
||||||
|
|
||||||
;; Projectile integration. Taken from tabbar-ruler
|
|
||||||
(defvar centaur-tabs-projectile-buffer-group-calc nil
|
|
||||||
"Set buffer groups for projectile.
|
|
||||||
Should be buffer local and speed up calculation of buffer groups.")
|
|
||||||
|
|
||||||
(defun centaur-tabs-projectile-buffer-groups ()
|
|
||||||
"Return the list of group names BUFFER belongs to."
|
|
||||||
(if centaur-tabs-projectile-buffer-group-calc
|
|
||||||
(symbol-value 'centaur-tabs-projectile-buffer-group-calc)
|
|
||||||
(set (make-local-variable 'centaur-tabs-projectile-buffer-group-calc)
|
|
||||||
|
|
||||||
(cond
|
|
||||||
((or (get-buffer-process (current-buffer)) (memq major-mode '(comint-mode compilation-mode))) '("Term"))
|
|
||||||
((string-equal "*" (substring (buffer-name) 0 1)) '("Misc"))
|
|
||||||
((condition-case _err
|
|
||||||
(projectile-project-root)
|
|
||||||
(error nil))
|
|
||||||
(list (projectile-project-name)))
|
|
||||||
((memq major-mode '(emacs-lisp-mode python-mode emacs-lisp-mode c-mode
|
|
||||||
c++-mode javascript-mode js-mode
|
|
||||||
js2-mode makefile-mode
|
|
||||||
lua-mode vala-mode))
|
|
||||||
'("Coding"))
|
|
||||||
((memq major-mode '( nxhtml-mode html-mode
|
|
||||||
mhtml-mode css-mode))
|
|
||||||
'("HTML"))
|
|
||||||
((memq major-mode '(org-mode calendar-mode diary-mode)) '("Org"))
|
|
||||||
((memq major-mode '(dired-mode)) '("Dir"))
|
|
||||||
(t '("Other"))))
|
|
||||||
(symbol-value 'centaur-tabs-projectile-buffer-group-calc)))
|
|
||||||
|
|
||||||
(defun centaur-tabs-group-by-projectile-project()
|
|
||||||
"Group by projectile project."
|
|
||||||
(interactive)
|
|
||||||
(setq centaur-tabs-buffer-groups-function 'centaur-tabs-projectile-buffer-groups)
|
|
||||||
(centaur-tabs-display-update))
|
|
||||||
|
|
||||||
;; Show groups instead of tabs
|
|
||||||
(defun centaur-tabs-toggle-groups ()
|
|
||||||
"Show group names on the tabs instead of buffer names."
|
|
||||||
(interactive)
|
|
||||||
(centaur-tabs-buffer-show-groups (not centaur-tabs--buffer-show-groups))
|
|
||||||
(centaur-tabs-display-update))
|
|
||||||
|
|
||||||
;; Helm source for switching group in helm.
|
|
||||||
|
|
||||||
(defun centaur-tabs-build-helm-source ()
|
|
||||||
"Display a list of current buffer groups in Helm."
|
|
||||||
(interactive)
|
|
||||||
(setq helm-source-centaur-tabs-group
|
|
||||||
(when (featurep 'helm)
|
|
||||||
(require 'helm)
|
|
||||||
(helm-build-sync-source "Centaur-Tabs Group"
|
|
||||||
:candidates #'centaur-tabs-get-groups
|
|
||||||
:action '(("Switch to group" . centaur-tabs-switch-group))))))
|
|
||||||
|
|
||||||
;; Ivy source for switching group in ivy.
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun centaur-tabs-counsel-switch-group ()
|
|
||||||
"Display a list of current buffer groups using Counsel."
|
|
||||||
(interactive)
|
|
||||||
(when (featurep 'ivy)
|
|
||||||
(require 'ivy)
|
|
||||||
(ivy-read
|
|
||||||
"Centaur Tabs Groups:"
|
|
||||||
(centaur-tabs-get-groups)
|
|
||||||
:action #'centaur-tabs-switch-group
|
|
||||||
:caller 'centaur-tabs-counsel-switch-group)))
|
|
||||||
|
|
||||||
(defun centaur-tabs-extract-window-to-new-frame()
|
|
||||||
"Kill the current window in the current frame, and open the current buffer
|
|
||||||
in a new frame."
|
|
||||||
(interactive)
|
|
||||||
(unless (centaur-tabs--one-window-p)
|
|
||||||
(let ((buffer (current-buffer)))
|
|
||||||
(delete-window)
|
|
||||||
(display-buffer-pop-up-frame buffer nil))))
|
|
||||||
|
|
||||||
(defun centaur-tabs--copy-file-name-to-clipboard ()
|
|
||||||
"Copy the current buffer file name to the clipboard."
|
|
||||||
;;; From https://emacsredux.com/blog/2013/03/27/copy-filename-to-the-clipboard/
|
|
||||||
(interactive)
|
|
||||||
(let* ((filename (if (equal major-mode 'dired-mode)
|
|
||||||
default-directory
|
|
||||||
(buffer-file-name)))
|
|
||||||
(filename (expand-file-name filename)))
|
|
||||||
(when filename
|
|
||||||
(kill-new filename)
|
|
||||||
(message "Copied buffer file name '%s' to the kill ring." filename))))
|
|
||||||
|
|
||||||
(defun centaur-tabs-open-directory-in-external-application ()
|
|
||||||
"Open the current directory in a external application."
|
|
||||||
(interactive)
|
|
||||||
(centaur-tabs--open-externally default-directory))
|
|
||||||
|
|
||||||
(defun centaur-tabs-open-in-external-application ()
|
|
||||||
"Open the file of the current buffer according to its mime type."
|
|
||||||
(interactive)
|
|
||||||
(let ((path (or (buffer-file-name) default-directory)))
|
|
||||||
(centaur-tabs--open-externally path)))
|
|
||||||
|
|
||||||
(defun centaur-tabs--open-externally (file-or-path)
|
|
||||||
"Open FILE-OR-PATH according to its mime type in an external application.
|
|
||||||
FILE-OR-PATH is expanded with `expand-file-name`.
|
|
||||||
Modified copy of `treemacs-visit-node-in-external-application`."
|
|
||||||
(let ((path (expand-file-name file-or-path)))
|
|
||||||
(pcase system-type
|
|
||||||
('windows-nt
|
|
||||||
(declare-function w32-shell-execute "w32fns.c")
|
|
||||||
(w32-shell-execute "open" (replace-regexp-in-string "/" "\\" path t t)))
|
|
||||||
('darwin
|
|
||||||
(shell-command (format "open \"%s\"" path)))
|
|
||||||
('gnu/linux
|
|
||||||
(let ((process-connection-type nil))
|
|
||||||
(start-process "" nil "xdg-open" path)))
|
|
||||||
(_ (message "Don't know how to open files on %s." (symbol-name system-type))))))
|
|
||||||
|
|
||||||
(defun centaur-tabs--copy-directory-name-to-clipboard ()
|
|
||||||
"Copy the current directory name to the clipboard."
|
|
||||||
(interactive)
|
|
||||||
(when default-directory
|
|
||||||
(kill-new default-directory)
|
|
||||||
(message "Copied directory name '%s' to the kill ring." (expand-file-name default-directory))))
|
|
||||||
|
|
||||||
(defun centaur-tabs--tab-submenu-groups-definition ()
|
|
||||||
"Menu definition with a list of tab groups."
|
|
||||||
(mapcar (lambda (s) `[,s ,s]) (sort (centaur-tabs-get-groups) #'string<)))
|
|
||||||
|
|
||||||
(defun centaur-tabs--tab-submenu-tabs-definition ()
|
|
||||||
"Menu definition with a list of tabs for the current group."
|
|
||||||
(let* ((tabset (centaur-tabs-get-tabset centaur-tabs-last-focused-buffer-group))
|
|
||||||
(tabs-in-group (centaur-tabs-tabs tabset))
|
|
||||||
(buffers (mapcar #'centaur-tabs-tab-value tabs-in-group))
|
|
||||||
(sorted-tabnames (sort (mapcar #'buffer-name buffers) #'string<)))
|
|
||||||
(mapcar (lambda (s) `[,s ,s]) sorted-tabnames)))
|
|
||||||
|
|
||||||
(defvar centaur-tabs--groups-submenu-key "Tab groups")
|
|
||||||
(defvar centaur-tabs--tabs-submenu-key "Go to tab of group")
|
|
||||||
|
|
||||||
(defun centaur-tabs--kill-this-buffer-dont-ask()
|
|
||||||
"Kill the current buffer without confirmation."
|
|
||||||
(interactive)
|
|
||||||
(kill-buffer (current-buffer))
|
|
||||||
(centaur-tabs-display-update)
|
|
||||||
(redisplay t))
|
|
||||||
|
|
||||||
(defun centaur-tabs--tab-menu-definition ()
|
|
||||||
"Definition of the context menu of a tab."
|
|
||||||
`(["Kill this buffer" centaur-tabs--kill-this-buffer-dont-ask]
|
|
||||||
["Kill other buffers of group" centaur-tabs-kill-other-buffers-in-current-group]
|
|
||||||
["Kill unmodified buffers of group" centaur-tabs-kill-unmodified-buffers-in-current-group]
|
|
||||||
"----"
|
|
||||||
["Split below" split-window-below]
|
|
||||||
["Split right" split-window-right]
|
|
||||||
"----"
|
|
||||||
["Maximize tab" delete-other-windows
|
|
||||||
:active (null (centaur-tabs--one-window-p))]
|
|
||||||
["Extract to new frame" centaur-tabs-extract-window-to-new-frame
|
|
||||||
:active (null (centaur-tabs--one-window-p))]
|
|
||||||
["Duplicate in new frame" make-frame-command]
|
|
||||||
"----"
|
|
||||||
["Copy filepath" centaur-tabs--copy-file-name-to-clipboard
|
|
||||||
:active (buffer-file-name)]
|
|
||||||
["Copy directory path" centaur-tabs--copy-directory-name-to-clipboard
|
|
||||||
:active default-directory]
|
|
||||||
["Open in external application" centaur-tabs-open-in-external-application
|
|
||||||
:active (or (buffer-file-name) default-directory)]
|
|
||||||
["Open directory in dired" dired-jump
|
|
||||||
:active (not (eq major-mode 'dired-mode))]
|
|
||||||
["Open directory externally" centaur-tabs-open-directory-in-external-application
|
|
||||||
:active default-directory]
|
|
||||||
"----"
|
|
||||||
,( append (list centaur-tabs--groups-submenu-key) (centaur-tabs--tab-submenu-groups-definition))
|
|
||||||
,( append (list centaur-tabs--tabs-submenu-key) (centaur-tabs--tab-submenu-tabs-definition))))
|
|
||||||
|
|
||||||
(defun centaur-tabs--one-window-p ()
|
|
||||||
"Like `one-window-p`, but taking into account side windows like treemacs."
|
|
||||||
(let* ((mainwindow (window-main-window))
|
|
||||||
(child-count (window-child-count mainwindow)))
|
|
||||||
(= 0 child-count)))
|
|
||||||
|
|
||||||
(defun centaur-tabs--get-tab-from-name (tabname)
|
|
||||||
"Get the tab from the current group given de TABNAME."
|
|
||||||
(let ((seq (centaur-tabs-tabs (centaur-tabs-get-tabset centaur-tabs-last-focused-buffer-group))))
|
|
||||||
(cl-find-if
|
|
||||||
(lambda (tab) (string= tabname (buffer-name (centaur-tabs-tab-value tab))))
|
|
||||||
seq)))
|
|
||||||
|
|
||||||
(defun centaur-tabs--tab-menu (event)
|
|
||||||
"Show a context menu for the clicked tab or button.
|
|
||||||
The clicked tab, identified by EVENT, is selected."
|
|
||||||
(interactive "e" )
|
|
||||||
(let ((click-on-tab-p (ignore-errors (centaur-tabs-get-tab-from-event event))))
|
|
||||||
(when (not click-on-tab-p)
|
|
||||||
(centaur-tabs--groups-menu))
|
|
||||||
(when click-on-tab-p
|
|
||||||
(centaur-tabs-do-select event)
|
|
||||||
(redisplay t)
|
|
||||||
(let*
|
|
||||||
((menu (easy-menu-create-menu nil (centaur-tabs--tab-menu-definition)))
|
|
||||||
(choice (x-popup-menu t menu))
|
|
||||||
(action (lookup-key menu (apply 'vector choice)))
|
|
||||||
(action-is-command-p (and (commandp action) (functionp action))))
|
|
||||||
(when action-is-command-p
|
|
||||||
(call-interactively action))
|
|
||||||
(when (not action-is-command-p)
|
|
||||||
(let* ((menu-key (cl-first choice))
|
|
||||||
(choice-is-group-p (string= centaur-tabs--groups-submenu-key (symbol-name menu-key)))
|
|
||||||
(name (car (last choice)))
|
|
||||||
(name-as-string (symbol-name name)))
|
|
||||||
(if choice-is-group-p
|
|
||||||
(centaur-tabs-switch-group name-as-string)
|
|
||||||
(switch-to-buffer name-as-string))))))))
|
|
||||||
|
|
||||||
(defun centaur-tabs--groups-menu ()
|
|
||||||
"Show a popup menu with the centaur tabs groups."
|
|
||||||
(interactive)
|
|
||||||
(let* ((sorted-groups (centaur-tabs--tab-submenu-groups-definition))
|
|
||||||
(menu (easy-menu-create-menu "Tab groups"
|
|
||||||
(centaur-tabs--tab-submenu-groups-definition)))
|
|
||||||
(choice (x-popup-menu t menu))
|
|
||||||
(action (lookup-key menu (apply 'vector choice)))
|
|
||||||
(action-is-command-p (and (commandp action) (functionp action))))
|
|
||||||
(when action-is-command-p
|
|
||||||
(call-interactively action))
|
|
||||||
(when (not action-is-command-p)
|
|
||||||
(let ((group (car (last choice))))
|
|
||||||
(centaur-tabs-switch-group (format "%s" group))))))
|
|
||||||
|
|
||||||
(provide 'centaur-tabs-interactive)
|
|
||||||
;;; centaur-tabs-interactive.el ends here
|
|
|
@ -1,15 +0,0 @@
|
||||||
(define-package "centaur-tabs" "20240726.625" "Aesthetic, modern looking customizable tabs plugin"
|
|
||||||
'((emacs "27.1")
|
|
||||||
(powerline "2.4"))
|
|
||||||
:commit "49b9f6b813dfb1fe78aa782f76b4a7333dd8f980" :authors
|
|
||||||
'(("Emmanuel Bustos" . "ema2159@gmail.com"))
|
|
||||||
:maintainers
|
|
||||||
'(("Jen-Chieh Shen" . "jcs090218@gmail.com"))
|
|
||||||
:maintainer
|
|
||||||
'("Jen-Chieh Shen" . "jcs090218@gmail.com")
|
|
||||||
:keywords
|
|
||||||
'("frames")
|
|
||||||
:url "https://github.com/ema2159/centaur-tabs")
|
|
||||||
;; Local Variables:
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; End:
|
|
|
@ -1,6 +1,6 @@
|
||||||
(define-package "dash" "20240510.1327" "A modern list library for Emacs"
|
(define-package "dash" "20240103.1301" "A modern list library for Emacs"
|
||||||
'((emacs "24"))
|
'((emacs "24"))
|
||||||
:commit "1de9dcb83eacfb162b6d9a118a4770b1281bcd84" :authors
|
:commit "e32a70ca636bad42232b6c79f1491dc86802a721" :authors
|
||||||
'(("Magnar Sveen" . "magnars@gmail.com"))
|
'(("Magnar Sveen" . "magnars@gmail.com"))
|
||||||
:maintainers
|
:maintainers
|
||||||
'(("Magnar Sveen" . "magnars@gmail.com"))
|
'(("Magnar Sveen" . "magnars@gmail.com"))
|
|
@ -2108,7 +2108,7 @@ last item in second form, etc."
|
||||||
|
|
||||||
Insert X at the position signified by the symbol `it' in the first
|
Insert X at the position signified by the symbol `it' in the first
|
||||||
form. If there are more forms, insert the first form at the position
|
form. If there are more forms, insert the first form at the position
|
||||||
signified by `it' in the second form, etc."
|
signified by `it' in in second form, etc."
|
||||||
(declare (debug (form body)))
|
(declare (debug (form body)))
|
||||||
`(-as-> ,x it ,@forms))
|
`(-as-> ,x it ,@forms))
|
||||||
|
|
||||||
|
@ -3298,8 +3298,6 @@ Return the sorted list. LIST is NOT modified by side effects.
|
||||||
COMPARATOR is called with two elements of LIST, and should return non-nil
|
COMPARATOR is called with two elements of LIST, and should return non-nil
|
||||||
if the first element should sort before the second."
|
if the first element should sort before the second."
|
||||||
(declare (important-return-value t))
|
(declare (important-return-value t))
|
||||||
;; Not yet worth changing to (sort list :lessp comparator);
|
|
||||||
;; still seems as fast or slightly faster.
|
|
||||||
(sort (copy-sequence list) comparator))
|
(sort (copy-sequence list) comparator))
|
||||||
|
|
||||||
(defmacro --sort (form list)
|
(defmacro --sort (form list)
|
|
@ -1,4 +1,4 @@
|
||||||
This is dash.info, produced by makeinfo version 6.8 from dash.texi.
|
This is dash.info, produced by makeinfo version 6.7 from dash.texi.
|
||||||
|
|
||||||
This manual is for Dash version 2.19.1.
|
This manual is for Dash version 2.19.1.
|
||||||
|
|
||||||
|
@ -2427,7 +2427,7 @@ readability.
|
||||||
|
|
||||||
Insert X at the position signified by the symbol ‘it’ in the first
|
Insert X at the position signified by the symbol ‘it’ in the first
|
||||||
form. If there are more forms, insert the first form at the
|
form. If there are more forms, insert the first form at the
|
||||||
position signified by ‘it’ in the second form, etc.
|
position signified by ‘it’ in in second form, etc.
|
||||||
|
|
||||||
(--> "def" (concat "abc" it "ghi"))
|
(--> "def" (concat "abc" it "ghi"))
|
||||||
⇒ "abcdefghi"
|
⇒ "abcdefghi"
|
||||||
|
@ -4892,53 +4892,53 @@ Node: Threading macros84441
|
||||||
Ref: ->84666
|
Ref: ->84666
|
||||||
Ref: ->>85154
|
Ref: ->>85154
|
||||||
Ref: -->85657
|
Ref: -->85657
|
||||||
Ref: -as->86214
|
Ref: -as->86213
|
||||||
Ref: -some->86668
|
Ref: -some->86667
|
||||||
Ref: -some->>87053
|
Ref: -some->>87052
|
||||||
Ref: -some-->87500
|
Ref: -some-->87499
|
||||||
Ref: -doto88067
|
Ref: -doto88066
|
||||||
Node: Binding88620
|
Node: Binding88619
|
||||||
Ref: -when-let88827
|
Ref: -when-let88826
|
||||||
Ref: -when-let*89288
|
Ref: -when-let*89287
|
||||||
Ref: -if-let89817
|
Ref: -if-let89816
|
||||||
Ref: -if-let*90183
|
Ref: -if-let*90182
|
||||||
Ref: -let90806
|
Ref: -let90805
|
||||||
Ref: -let*96896
|
Ref: -let*96895
|
||||||
Ref: -lambda97833
|
Ref: -lambda97832
|
||||||
Ref: -setq98639
|
Ref: -setq98638
|
||||||
Node: Side effects99440
|
Node: Side effects99439
|
||||||
Ref: -each99634
|
Ref: -each99633
|
||||||
Ref: -each-while100161
|
Ref: -each-while100160
|
||||||
Ref: -each-indexed100781
|
Ref: -each-indexed100780
|
||||||
Ref: -each-r101373
|
Ref: -each-r101372
|
||||||
Ref: -each-r-while101815
|
Ref: -each-r-while101814
|
||||||
Ref: -dotimes102459
|
Ref: -dotimes102458
|
||||||
Node: Destructive operations103012
|
Node: Destructive operations103011
|
||||||
Ref: !cons103230
|
Ref: !cons103229
|
||||||
Ref: !cdr103434
|
Ref: !cdr103433
|
||||||
Node: Function combinators103627
|
Node: Function combinators103626
|
||||||
Ref: -partial103831
|
Ref: -partial103830
|
||||||
Ref: -rpartial104349
|
Ref: -rpartial104348
|
||||||
Ref: -juxt104997
|
Ref: -juxt104996
|
||||||
Ref: -compose105449
|
Ref: -compose105448
|
||||||
Ref: -applify106056
|
Ref: -applify106055
|
||||||
Ref: -on106486
|
Ref: -on106485
|
||||||
Ref: -flip107258
|
Ref: -flip107257
|
||||||
Ref: -rotate-args107782
|
Ref: -rotate-args107781
|
||||||
Ref: -const108411
|
Ref: -const108410
|
||||||
Ref: -cut108753
|
Ref: -cut108752
|
||||||
Ref: -not109233
|
Ref: -not109232
|
||||||
Ref: -orfn109777
|
Ref: -orfn109776
|
||||||
Ref: -andfn110570
|
Ref: -andfn110569
|
||||||
Ref: -iteratefn111357
|
Ref: -iteratefn111356
|
||||||
Ref: -fixfn112059
|
Ref: -fixfn112058
|
||||||
Ref: -prodfn113633
|
Ref: -prodfn113632
|
||||||
Node: Development114784
|
Node: Development114783
|
||||||
Node: Contribute115073
|
Node: Contribute115072
|
||||||
Node: Contributors116085
|
Node: Contributors116084
|
||||||
Node: FDL118178
|
Node: FDL118177
|
||||||
Node: GPL143498
|
Node: GPL143497
|
||||||
Node: Index181247
|
Node: Index181246
|
||||||
|
|
||||||
End Tag Table
|
End Tag Table
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
(define-package "dash" "20240510.1327" "A modern list library for Emacs"
|
|
||||||
'((emacs "24"))
|
|
||||||
:commit "1de9dcb83eacfb162b6d9a118a4770b1281bcd84" :authors
|
|
||||||
'(("Magnar Sveen" . "magnars@gmail.com"))
|
|
||||||
:maintainers
|
|
||||||
'(("Magnar Sveen" . "magnars@gmail.com"))
|
|
||||||
:maintainer
|
|
||||||
'("Magnar Sveen" . "magnars@gmail.com")
|
|
||||||
:keywords
|
|
||||||
'("extensions" "lisp")
|
|
||||||
:url "https://github.com/magnars/dash.el")
|
|
||||||
;; Local Variables:
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; End:
|
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
@ -1,10 +1,9 @@
|
||||||
(define-package "dashboard" "20240529.2058" "A startup screen extracted from Spacemacs"
|
(define-package "dashboard" "20240319.915" "A startup screen extracted from Spacemacs"
|
||||||
'((emacs "26.1"))
|
'((emacs "26.1"))
|
||||||
:commit "3852301f9c6f3104d9cc98389612b5ef3452a7de" :authors
|
:commit "e34ce1b4730fb88a33a571b9065114b7a77645f0" :authors
|
||||||
'(("Rakan Al-Hneiti" . "rakan.alhneiti@gmail.com"))
|
'(("Rakan Al-Hneiti" . "rakan.alhneiti@gmail.com"))
|
||||||
:maintainers
|
:maintainers
|
||||||
'(("Jesús Martínez" . "jesusmartinez93@gmail.com")
|
'(("Jesús Martínez" . "jesusmartinez93@gmail.com"))
|
||||||
("Jen-Chieh" . "jcs090218@gmail.com"))
|
|
||||||
:maintainer
|
:maintainer
|
||||||
'("Jesús Martínez" . "jesusmartinez93@gmail.com")
|
'("Jesús Martínez" . "jesusmartinez93@gmail.com")
|
||||||
:keywords
|
:keywords
|
|
@ -70,6 +70,15 @@
|
||||||
(declare-function string-pixel-width "subr-x.el") ; TODO: remove this after 29.1
|
(declare-function string-pixel-width "subr-x.el") ; TODO: remove this after 29.1
|
||||||
(declare-function shr-string-pixel-width "shr.el") ; TODO: remove this after 29.1
|
(declare-function shr-string-pixel-width "shr.el") ; TODO: remove this after 29.1
|
||||||
|
|
||||||
|
(make-obsolete-variable 'dashboard-set-navigator
|
||||||
|
'dashboard-startupify-list "1.9.0")
|
||||||
|
|
||||||
|
(make-obsolete-variable 'dashboard-set-init-info
|
||||||
|
'dashboard-startupify-list "1.9.0")
|
||||||
|
|
||||||
|
(make-obsolete-variable 'dashboard-set-footer
|
||||||
|
'dashboard-startupify-list "1.9.0")
|
||||||
|
|
||||||
(defvar recentf-list nil)
|
(defvar recentf-list nil)
|
||||||
|
|
||||||
(defvar dashboard-buffer-name)
|
(defvar dashboard-buffer-name)
|
||||||
|
@ -124,27 +133,6 @@ See `create-image' and Info node `(elisp)Image Descriptors'."
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:group 'dashboard)
|
:group 'dashboard)
|
||||||
|
|
||||||
(defcustom dashboard-set-navigator nil
|
|
||||||
"When non nil, a navigator will be displayed under the banner."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'dashboard)
|
|
||||||
(make-obsolete-variable 'dashboard-set-navigator
|
|
||||||
'dashboard-startupify-list "1.9.0")
|
|
||||||
|
|
||||||
(defcustom dashboard-set-init-info t
|
|
||||||
"When non nil, init info will be displayed under the banner."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'dashboard)
|
|
||||||
(make-obsolete-variable 'dashboard-set-init-info
|
|
||||||
'dashboard-startupify-list "1.9.0")
|
|
||||||
|
|
||||||
(defcustom dashboard-set-footer t
|
|
||||||
"When non nil, a footer will be displayed at the bottom."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'dashboard)
|
|
||||||
(make-obsolete-variable 'dashboard-set-footer
|
|
||||||
'dashboard-startupify-list "1.9.0")
|
|
||||||
|
|
||||||
(defcustom dashboard-footer-messages
|
(defcustom dashboard-footer-messages
|
||||||
'("The one true editor, Emacs!"
|
'("The one true editor, Emacs!"
|
||||||
"Who the hell uses VIM anyway? Go Evil!"
|
"Who the hell uses VIM anyway? Go Evil!"
|
||||||
|
@ -193,7 +181,7 @@ The value can be one of: `all-the-icons', `nerd-icons'."
|
||||||
Will be of the form `(list-type . icon-name-string)`.
|
Will be of the form `(list-type . icon-name-string)`.
|
||||||
If nil it is disabled. Possible values for list-type are:
|
If nil it is disabled. Possible values for list-type are:
|
||||||
`recents' `bookmarks' `projects' `agenda' `registers'"
|
`recents' `bookmarks' `projects' `agenda' `registers'"
|
||||||
:type '(alist :key-type symbol :value-type string)
|
:type '(repeat (alist :key-type symbol :value-type string))
|
||||||
:group 'dashboard)
|
:group 'dashboard)
|
||||||
|
|
||||||
(defcustom dashboard-heading-icon-height 1.2
|
(defcustom dashboard-heading-icon-height 1.2
|
||||||
|
@ -257,16 +245,7 @@ The format is: `icon title help action face prefix suffix`.
|
||||||
Example:
|
Example:
|
||||||
`((\"☆\" \"Star\" \"Show stars\" (lambda (&rest _)
|
`((\"☆\" \"Star\" \"Show stars\" (lambda (&rest _)
|
||||||
(show-stars)) warning \"[\" \"]\"))"
|
(show-stars)) warning \"[\" \"]\"))"
|
||||||
:type '(repeat (repeat (list string
|
:type '(repeat (repeat (list string string string function symbol string string)))
|
||||||
string
|
|
||||||
string
|
|
||||||
function
|
|
||||||
(choice face
|
|
||||||
(repeat :tag "Anonymous face" sexp))
|
|
||||||
(choice string
|
|
||||||
(const nil))
|
|
||||||
(choice string
|
|
||||||
(const nil)))))
|
|
||||||
:group 'dashboard)
|
:group 'dashboard)
|
||||||
|
|
||||||
(defcustom dashboard-init-info
|
(defcustom dashboard-init-info
|
||||||
|
@ -356,10 +335,8 @@ ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties.
|
||||||
:v-adjust -0.05
|
:v-adjust -0.05
|
||||||
:face 'dashboard-footer-icon-face)))
|
:face 'dashboard-footer-icon-face)))
|
||||||
(propertize ">" 'face 'dashboard-footer-icon-face))
|
(propertize ">" 'face 'dashboard-footer-icon-face))
|
||||||
"Footer's icon.
|
"Footer's icon."
|
||||||
It can be a string or a string list for display random icons."
|
:type 'string
|
||||||
:type '(choice string
|
|
||||||
(repeat string))
|
|
||||||
:group 'dashboard)
|
:group 'dashboard)
|
||||||
|
|
||||||
(defcustom dashboard-heading-shorcut-format " (%s)"
|
(defcustom dashboard-heading-shorcut-format " (%s)"
|
||||||
|
@ -434,9 +411,7 @@ installed."
|
||||||
Will be of the form `(list-type . list-size)'.
|
Will be of the form `(list-type . list-size)'.
|
||||||
If nil it is disabled. Possible values for list-type are:
|
If nil it is disabled. Possible values for list-type are:
|
||||||
`recents' `bookmarks' `projects' `agenda' `registers'."
|
`recents' `bookmarks' `projects' `agenda' `registers'."
|
||||||
:type '(repeat (choice
|
:type '(repeat (alist :key-type symbol :value-type integer))
|
||||||
symbol
|
|
||||||
(cons symbol integer)))
|
|
||||||
:group 'dashboard)
|
:group 'dashboard)
|
||||||
|
|
||||||
(defcustom dashboard-item-shortcuts
|
(defcustom dashboard-item-shortcuts
|
||||||
|
@ -448,8 +423,8 @@ If nil it is disabled. Possible values for list-type are:
|
||||||
"Association list of items and their corresponding shortcuts.
|
"Association list of items and their corresponding shortcuts.
|
||||||
Will be of the form `(list-type . keys)' as understood by `(kbd keys)'.
|
Will be of the form `(list-type . keys)' as understood by `(kbd keys)'.
|
||||||
If nil, shortcuts are disabled. If an entry's value is nil, that item's
|
If nil, shortcuts are disabled. If an entry's value is nil, that item's
|
||||||
shortcut is disabled. See `dashboard-items' for possible values of list-type.'"
|
shortcut is disbaled. See `dashboard-items' for possible values of list-type.'"
|
||||||
:type '(alist :key-type symbol :value-type string)
|
:type '(repeat (alist :key-type symbol :value-type string))
|
||||||
:group 'dashboard)
|
:group 'dashboard)
|
||||||
|
|
||||||
(defcustom dashboard-item-names nil
|
(defcustom dashboard-item-names nil
|
||||||
|
@ -599,8 +574,7 @@ Optionally, provide NO-NEXT-LINE to move the cursor forward a line."
|
||||||
`(progn
|
`(progn
|
||||||
(eval-when-compile (defvar dashboard-mode-map))
|
(eval-when-compile (defvar dashboard-mode-map))
|
||||||
(defun ,sym nil
|
(defun ,sym nil
|
||||||
,(concat "Jump to " name ".
|
,(concat "Jump to " name ". This code is dynamically generated in `dashboard-insert-shortcut'.")
|
||||||
This code is dynamically generated in `dashboard-insert-shortcut'.")
|
|
||||||
(interactive)
|
(interactive)
|
||||||
(unless (search-forward ,search-label (point-max) t)
|
(unless (search-forward ,search-label (point-max) t)
|
||||||
(search-backward ,search-label (point-min) t))
|
(search-backward ,search-label (point-min) t))
|
||||||
|
@ -625,12 +599,9 @@ If MESSAGEBUF is not nil then MSG is also written in message buffer."
|
||||||
"Insert a page break line in dashboard buffer."
|
"Insert a page break line in dashboard buffer."
|
||||||
(dashboard-append dashboard-page-separator))
|
(dashboard-append dashboard-page-separator))
|
||||||
|
|
||||||
(defun dashboard-insert-newline (&optional times)
|
(defun dashboard-insert-newline (&optional n)
|
||||||
"When called without an argument, insert a newline.
|
"Insert N times of newlines."
|
||||||
When called with TIMES return a function that insert TIMES number of newlines."
|
(dotimes (_ (or n 1))
|
||||||
(if times
|
|
||||||
(lambda ()
|
|
||||||
(insert (make-string times (string-to-char "\n") t)))
|
|
||||||
(insert "\n")))
|
(insert "\n")))
|
||||||
|
|
||||||
(defun dashboard-insert-heading (heading &optional shortcut icon)
|
(defun dashboard-insert-heading (heading &optional shortcut icon)
|
||||||
|
@ -744,9 +715,7 @@ When called with TIMES return a function that insert TIMES number of newlines."
|
||||||
(list :text (dashboard-get-banner-path 1)))))
|
(list :text (dashboard-get-banner-path 1)))))
|
||||||
((and
|
((and
|
||||||
(pred listp)
|
(pred listp)
|
||||||
(pred (lambda (c)
|
(pred (lambda (c) (not (proper-list-p c))))
|
||||||
(and (not (proper-list-p c))
|
|
||||||
(not (null c)))))
|
|
||||||
`(,img . ,txt))
|
`(,img . ,txt))
|
||||||
(list :image (if (dashboard--image-supported-p img)
|
(list :image (if (dashboard--image-supported-p img)
|
||||||
img
|
img
|
||||||
|
@ -756,16 +725,12 @@ When called with TIMES return a function that insert TIMES number of newlines."
|
||||||
txt
|
txt
|
||||||
(message "could not find banner %s, use default instead" txt)
|
(message "could not find banner %s, use default instead" txt)
|
||||||
(dashboard-get-banner-path 1))))
|
(dashboard-get-banner-path 1))))
|
||||||
((and
|
((pred proper-list-p)
|
||||||
(pred proper-list-p)
|
|
||||||
(pred (lambda (l) (not (null l)))))
|
|
||||||
|
|
||||||
(let* ((max (length banner))
|
(let* ((max (length banner))
|
||||||
(choose (nth (random max) banner)))
|
(choose (nth (random max) banner)))
|
||||||
(dashboard-choose-banner choose)))
|
(dashboard-choose-banner choose)))
|
||||||
(_
|
(_
|
||||||
(user-error "Unsupported banner type: `%s'" banner)
|
(message "unsupported banner config %s" banner))))
|
||||||
nil)))
|
|
||||||
|
|
||||||
(defun dashboard--image-animated-p (image-path)
|
(defun dashboard--image-animated-p (image-path)
|
||||||
"Return if image is a gif or webp.
|
"Return if image is a gif or webp.
|
||||||
|
@ -885,8 +850,7 @@ Argument IMAGE-PATH path to the image."
|
||||||
(when (and icon title
|
(when (and icon title
|
||||||
(not (string-equal icon ""))
|
(not (string-equal icon ""))
|
||||||
(not (string-equal title "")))
|
(not (string-equal title "")))
|
||||||
(propertize " " 'face `(:inherit (variable-pitch
|
(propertize " " 'face 'variable-pitch))
|
||||||
,face))))
|
|
||||||
(when title (propertize title 'face face)))
|
(when title (propertize title 'face face)))
|
||||||
:help-echo help
|
:help-echo help
|
||||||
:action action
|
:action action
|
||||||
|
@ -908,10 +872,7 @@ ACTION is theaction taken when the user activates the widget button.
|
||||||
WIDGET-PARAMS are passed to the \"widget-create\" function."
|
WIDGET-PARAMS are passed to the \"widget-create\" function."
|
||||||
`(progn
|
`(progn
|
||||||
(dashboard-insert-heading ,section-name
|
(dashboard-insert-heading ,section-name
|
||||||
(when (and ,list
|
(if (and ,list ,shortcut-char dashboard-show-shortcuts) ,shortcut-char))
|
||||||
,shortcut-char
|
|
||||||
dashboard-show-shortcuts)
|
|
||||||
,shortcut-char))
|
|
||||||
(if ,list
|
(if ,list
|
||||||
(when (and (dashboard-insert-section-list
|
(when (and (dashboard-insert-section-list
|
||||||
,section-name
|
,section-name
|
||||||
|
@ -967,19 +928,10 @@ to widget creation."
|
||||||
"Return a random footer from `dashboard-footer-messages'."
|
"Return a random footer from `dashboard-footer-messages'."
|
||||||
(nth (random (length dashboard-footer-messages)) dashboard-footer-messages))
|
(nth (random (length dashboard-footer-messages)) dashboard-footer-messages))
|
||||||
|
|
||||||
(defun dashboard-footer-icon ()
|
|
||||||
"Return footer icon or a random icon if `dashboard-footer-messages' is a list."
|
|
||||||
(if (and (not (null dashboard-footer-icon))
|
|
||||||
(listp dashboard-footer-icon))
|
|
||||||
(dashboard-replace-displayable
|
|
||||||
(nth (random (length dashboard-footer-icon))
|
|
||||||
dashboard-footer-icon))
|
|
||||||
(dashboard-replace-displayable dashboard-footer-icon)))
|
|
||||||
|
|
||||||
(defun dashboard-insert-footer ()
|
(defun dashboard-insert-footer ()
|
||||||
"Insert footer of dashboard."
|
"Insert footer of dashboard."
|
||||||
(when-let ((footer (dashboard-random-footer))
|
(when-let ((footer (dashboard-random-footer))
|
||||||
(footer-icon (dashboard-footer-icon)))
|
(footer-icon (dashboard-replace-displayable dashboard-footer-icon)))
|
||||||
(dashboard-insert-center
|
(dashboard-insert-center
|
||||||
(if (string-empty-p footer-icon) footer-icon
|
(if (string-empty-p footer-icon) footer-icon
|
||||||
(concat footer-icon " "))
|
(concat footer-icon " "))
|
||||||
|
@ -1388,9 +1340,7 @@ Any custom function would receives the tags from `org-get-tags'"
|
||||||
|
|
||||||
(defun dashboard-agenda-entry-format ()
|
(defun dashboard-agenda-entry-format ()
|
||||||
"Format agenda entry to show it on dashboard.
|
"Format agenda entry to show it on dashboard.
|
||||||
|
Also,it set text properties that latter are used to sort entries and perform different actions."
|
||||||
Also,it set text properties that latter are used to sort entries and perform
|
|
||||||
different actions."
|
|
||||||
(let* ((scheduled-time (org-get-scheduled-time (point)))
|
(let* ((scheduled-time (org-get-scheduled-time (point)))
|
||||||
(deadline-time (org-get-deadline-time (point)))
|
(deadline-time (org-get-deadline-time (point)))
|
||||||
(entry-timestamp (dashboard-agenda--entry-timestamp (point)))
|
(entry-timestamp (dashboard-agenda--entry-timestamp (point)))
|
|
@ -132,7 +132,7 @@
|
||||||
dashboard-insert-items
|
dashboard-insert-items
|
||||||
dashboard-insert-newline
|
dashboard-insert-newline
|
||||||
dashboard-insert-footer)
|
dashboard-insert-footer)
|
||||||
"List of dashboard widgets (in order) to insert in dashboard buffer.
|
"List of dashboard widgets (in order) to insert in dashboard buffer.
|
||||||
Avalaible functions:
|
Avalaible functions:
|
||||||
`dashboard-insert-newline'
|
`dashboard-insert-newline'
|
||||||
`dashboard-insert-page-break'
|
`dashboard-insert-page-break'
|
||||||
|
@ -143,15 +143,10 @@ Avalaible functions:
|
||||||
`dashboard-insert-items'
|
`dashboard-insert-items'
|
||||||
`dashboard-insert-footer'
|
`dashboard-insert-footer'
|
||||||
|
|
||||||
It must be a function or a cons cell where specify function and
|
You can also add your custom function or a lambda to the list.
|
||||||
its arg.
|
|
||||||
|
|
||||||
Also you can add your custom function or a lambda to the list.
|
|
||||||
example:
|
example:
|
||||||
(lambda () (delete-char -1))"
|
(lambda () (delete-char -1))"
|
||||||
:type '(repeat (choice
|
:type '(repeat function)
|
||||||
function
|
|
||||||
(cons function sexp)))
|
|
||||||
:group 'dashboard)
|
:group 'dashboard)
|
||||||
|
|
||||||
(defcustom dashboard-navigation-cycle nil
|
(defcustom dashboard-navigation-cycle nil
|
||||||
|
@ -159,10 +154,8 @@ example:
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:group 'dashboard)
|
:group 'dashboard)
|
||||||
|
|
||||||
(defcustom dashboard-buffer-name "*dashboard*"
|
(defconst dashboard-buffer-name "*dashboard*"
|
||||||
"Dashboard's buffer name."
|
"Dashboard's buffer name.")
|
||||||
:type 'string
|
|
||||||
:group 'dashboard)
|
|
||||||
|
|
||||||
(defvar dashboard-force-refresh nil
|
(defvar dashboard-force-refresh nil
|
||||||
"If non-nil, force refresh dashboard buffer.")
|
"If non-nil, force refresh dashboard buffer.")
|
||||||
|
@ -198,16 +191,16 @@ example:
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(if-let* ((sep (dashboard--separator))
|
(if-let* ((sep (dashboard--separator))
|
||||||
((and (search-backward sep nil t)
|
((and (search-backward sep nil t)
|
||||||
(search-forward sep nil t)))
|
(search-forward sep nil t))))
|
||||||
(ln (thing-at-point 'line t)))
|
(let ((ln (thing-at-point 'line)))
|
||||||
(cond ((string-match-p "Recent Files:" ln) 'recents)
|
(cond ((string-match-p "Recent Files:" ln) 'recents)
|
||||||
((string-match-p "Bookmarks:" ln) 'bookmarks)
|
((string-match-p "Bookmarks:" ln) 'bookmarks)
|
||||||
((string-match-p "Projects:" ln) 'projects)
|
((string-match-p "Projects:" ln) 'projects)
|
||||||
((string-match-p "Agenda for " ln) 'agenda)
|
((string-match-p "Agenda for " ln) 'agenda)
|
||||||
((string-match-p "Registers:" ln) 'registers)
|
((string-match-p "Registers:" ln) 'registers)
|
||||||
((string-match-p "List Directories:" ln) 'ls-directories)
|
((string-match-p "List Directories:" ln) 'ls-directories)
|
||||||
((string-match-p "List Files:" ln) 'ls-files)
|
((string-match-p "List Files:" ln) 'ls-files)
|
||||||
(t (user-error "Unknown section from dashboard")))
|
(t (user-error "Unknown section from dashboard"))))
|
||||||
(user-error "Failed searching dashboard section"))))
|
(user-error "Failed searching dashboard section"))))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
@ -507,11 +500,8 @@ See `dashboard-item-generators' for all items available."
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(setq dashboard--section-starts nil)
|
(setq dashboard--section-starts nil)
|
||||||
|
|
||||||
(mapc (lambda (entry)
|
(mapc (lambda (fn)
|
||||||
(if (and (listp entry)
|
(funcall fn))
|
||||||
(not (functionp entry)))
|
|
||||||
(apply (car entry) `(,(cdr entry)))
|
|
||||||
(funcall entry)))
|
|
||||||
dashboard-startupify-list)
|
dashboard-startupify-list)
|
||||||
|
|
||||||
(when dashboard-vertically-center-content
|
(when dashboard-vertically-center-content
|
File diff suppressed because it is too large
Load diff
|
@ -1,566 +0,0 @@
|
||||||
;;; dashboard.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*-
|
|
||||||
|
|
||||||
;; Copyright (c) 2016-2024 emacs-dashboard maintainers
|
|
||||||
;;
|
|
||||||
;; Author : Rakan Al-Hneiti <rakan.alhneiti@gmail.com>
|
|
||||||
;; Maintainer : Jesús Martínez <jesusmartinez93@gmail.com>
|
|
||||||
;; Shen, Jen-Chieh <jcs090218@gmail.com>
|
|
||||||
;; URL : https://github.com/emacs-dashboard/emacs-dashboard
|
|
||||||
;;
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
;;
|
|
||||||
;;; License: GPLv3
|
|
||||||
;;
|
|
||||||
;; Created: October 05, 2016
|
|
||||||
;; Package-Version: 1.9.0-SNAPSHOT
|
|
||||||
;; Keywords: startup, screen, tools, dashboard
|
|
||||||
;; Package-Requires: ((emacs "26.1"))
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; An extensible Emacs dashboard, with sections for
|
|
||||||
;; bookmarks, projects (projectile or project.el), org-agenda and more.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'ffap)
|
|
||||||
(require 'recentf)
|
|
||||||
|
|
||||||
(require 'dashboard-widgets)
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Externals
|
|
||||||
|
|
||||||
(declare-function bookmark-get-filename "ext:bookmark.el")
|
|
||||||
(declare-function bookmark-all-names "ext:bookmark.el")
|
|
||||||
(declare-function dashboard-ls--dirs "ext:dashboard-ls.el")
|
|
||||||
(declare-function dashboard-ls--files "ext:dashboard-ls.el")
|
|
||||||
(declare-function page-break-lines-mode "ext:page-break-lines.el")
|
|
||||||
(declare-function projectile-remove-known-project "ext:projectile.el")
|
|
||||||
(declare-function project-forget-projects-under "ext:project.el")
|
|
||||||
(declare-function linum-mode "linum.el")
|
|
||||||
|
|
||||||
(declare-function dashboard-refresh-buffer "dashboard.el")
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Customization
|
|
||||||
|
|
||||||
(defgroup dashboard nil
|
|
||||||
"Extensible startup screen."
|
|
||||||
:group 'applications)
|
|
||||||
|
|
||||||
;; Custom splash screen
|
|
||||||
(defvar dashboard-mode-map
|
|
||||||
(let ((map (make-sparse-keymap)))
|
|
||||||
(define-key map (kbd "C-p") #'dashboard-previous-line)
|
|
||||||
(define-key map (kbd "C-n") #'dashboard-next-line)
|
|
||||||
(define-key map (kbd "<up>") #'dashboard-previous-line)
|
|
||||||
(define-key map (kbd "<down>") #'dashboard-next-line)
|
|
||||||
(define-key map (kbd "k") #'dashboard-previous-line)
|
|
||||||
(define-key map (kbd "j") #'dashboard-next-line)
|
|
||||||
(define-key map [tab] #'widget-forward)
|
|
||||||
(define-key map (kbd "C-i") #'widget-forward)
|
|
||||||
(define-key map [backtab] #'widget-backward)
|
|
||||||
(define-key map (kbd "RET") #'dashboard-return)
|
|
||||||
(define-key map [mouse-1] #'dashboard-mouse-1)
|
|
||||||
(define-key map (kbd "}") #'dashboard-next-section)
|
|
||||||
(define-key map (kbd "{") #'dashboard-previous-section)
|
|
||||||
|
|
||||||
(define-key map (kbd "<backspace>") #'dashboard-remove-item-under)
|
|
||||||
(define-key map (kbd "<delete>") #'dashboard-remove-item-under)
|
|
||||||
(define-key map (kbd "DEL") #'dashboard-remove-item-under)
|
|
||||||
|
|
||||||
(define-key map (kbd "1") #'dashboard-section-1)
|
|
||||||
(define-key map (kbd "2") #'dashboard-section-2)
|
|
||||||
(define-key map (kbd "3") #'dashboard-section-3)
|
|
||||||
(define-key map (kbd "4") #'dashboard-section-4)
|
|
||||||
(define-key map (kbd "5") #'dashboard-section-5)
|
|
||||||
(define-key map (kbd "6") #'dashboard-section-6)
|
|
||||||
(define-key map (kbd "7") #'dashboard-section-7)
|
|
||||||
(define-key map (kbd "8") #'dashboard-section-8)
|
|
||||||
(define-key map (kbd "9") #'dashboard-section-9)
|
|
||||||
map)
|
|
||||||
"Keymap for dashboard mode.")
|
|
||||||
|
|
||||||
(defcustom dashboard-before-initialize-hook nil
|
|
||||||
"Hook that is run before dashboard buffer is initialized."
|
|
||||||
:group 'dashboard
|
|
||||||
:type 'hook)
|
|
||||||
|
|
||||||
(defcustom dashboard-after-initialize-hook nil
|
|
||||||
"Hook that is run after dashboard buffer is initialized."
|
|
||||||
:group 'dashboard
|
|
||||||
:type 'hook)
|
|
||||||
|
|
||||||
(defcustom dashboard-hide-cursor nil
|
|
||||||
"Whether to hide the cursor in the dashboard."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'dashboard)
|
|
||||||
|
|
||||||
(define-derived-mode dashboard-mode special-mode "Dashboard"
|
|
||||||
"Dashboard major mode for startup screen."
|
|
||||||
:group 'dashboard
|
|
||||||
:syntax-table nil
|
|
||||||
:abbrev-table nil
|
|
||||||
(buffer-disable-undo)
|
|
||||||
(when (featurep 'whitespace) (whitespace-mode -1))
|
|
||||||
(when (featurep 'linum) (linum-mode -1))
|
|
||||||
(when (featurep 'display-line-numbers) (display-line-numbers-mode -1))
|
|
||||||
(when (featurep 'page-break-lines) (page-break-lines-mode 1))
|
|
||||||
(setq-local revert-buffer-function #'dashboard-refresh-buffer)
|
|
||||||
(when dashboard-hide-cursor
|
|
||||||
(setq-local cursor-type nil))
|
|
||||||
(setq inhibit-startup-screen t
|
|
||||||
buffer-read-only t
|
|
||||||
truncate-lines t))
|
|
||||||
|
|
||||||
(defcustom dashboard-center-content nil
|
|
||||||
"Whether to center content within the window."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'dashboard)
|
|
||||||
|
|
||||||
(defcustom dashboard-vertically-center-content nil
|
|
||||||
"Whether to vertically center content within the window."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'dashboard)
|
|
||||||
|
|
||||||
(defcustom dashboard-startupify-list
|
|
||||||
'(dashboard-insert-banner
|
|
||||||
dashboard-insert-newline
|
|
||||||
dashboard-insert-banner-title
|
|
||||||
dashboard-insert-newline
|
|
||||||
dashboard-insert-init-info
|
|
||||||
dashboard-insert-items
|
|
||||||
dashboard-insert-newline
|
|
||||||
dashboard-insert-footer)
|
|
||||||
"List of dashboard widgets (in order) to insert in dashboard buffer.
|
|
||||||
Avalaible functions:
|
|
||||||
`dashboard-insert-newline'
|
|
||||||
`dashboard-insert-page-break'
|
|
||||||
`dashboard-insert-banner'
|
|
||||||
`dashboard-insert-banner-title'
|
|
||||||
`dashboard-insert-navigator'
|
|
||||||
`dashboard-insert-init-info'
|
|
||||||
`dashboard-insert-items'
|
|
||||||
`dashboard-insert-footer'
|
|
||||||
|
|
||||||
It must be a function or a cons cell where specify function and
|
|
||||||
its arg.
|
|
||||||
|
|
||||||
Also you can add your custom function or a lambda to the list.
|
|
||||||
example:
|
|
||||||
(lambda () (delete-char -1))"
|
|
||||||
:type '(repeat (choice
|
|
||||||
function
|
|
||||||
(cons function sexp)))
|
|
||||||
:group 'dashboard)
|
|
||||||
|
|
||||||
(defcustom dashboard-navigation-cycle nil
|
|
||||||
"Non-nil cycle the section navigation."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'dashboard)
|
|
||||||
|
|
||||||
(defcustom dashboard-buffer-name "*dashboard*"
|
|
||||||
"Dashboard's buffer name."
|
|
||||||
:type 'string
|
|
||||||
:group 'dashboard)
|
|
||||||
|
|
||||||
(defvar dashboard-force-refresh nil
|
|
||||||
"If non-nil, force refresh dashboard buffer.")
|
|
||||||
|
|
||||||
(defvar dashboard--section-starts nil
|
|
||||||
"List of section starting positions.")
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Util
|
|
||||||
|
|
||||||
(defun dashboard--goto-line (line)
|
|
||||||
"Goto LINE."
|
|
||||||
(goto-char (point-min)) (forward-line (1- line)))
|
|
||||||
|
|
||||||
(defmacro dashboard--save-excursion (&rest body)
|
|
||||||
"Execute BODY save window point."
|
|
||||||
(declare (indent 0) (debug t))
|
|
||||||
`(let ((line (line-number-at-pos nil t))
|
|
||||||
(column (current-column)))
|
|
||||||
,@body
|
|
||||||
(dashboard--goto-line line)
|
|
||||||
(move-to-column column)))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Core
|
|
||||||
|
|
||||||
(defun dashboard--separator ()
|
|
||||||
"Return separator used to search."
|
|
||||||
(concat "\n" dashboard-page-separator))
|
|
||||||
|
|
||||||
(defun dashboard--current-section ()
|
|
||||||
"Return section symbol in dashboard."
|
|
||||||
(save-excursion
|
|
||||||
(if-let* ((sep (dashboard--separator))
|
|
||||||
((and (search-backward sep nil t)
|
|
||||||
(search-forward sep nil t)))
|
|
||||||
(ln (thing-at-point 'line t)))
|
|
||||||
(cond ((string-match-p "Recent Files:" ln) 'recents)
|
|
||||||
((string-match-p "Bookmarks:" ln) 'bookmarks)
|
|
||||||
((string-match-p "Projects:" ln) 'projects)
|
|
||||||
((string-match-p "Agenda for " ln) 'agenda)
|
|
||||||
((string-match-p "Registers:" ln) 'registers)
|
|
||||||
((string-match-p "List Directories:" ln) 'ls-directories)
|
|
||||||
((string-match-p "List Files:" ln) 'ls-files)
|
|
||||||
(t (user-error "Unknown section from dashboard")))
|
|
||||||
(user-error "Failed searching dashboard section"))))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Navigation
|
|
||||||
|
|
||||||
(defun dashboard-previous-section ()
|
|
||||||
"Navigate forward to next section."
|
|
||||||
(interactive)
|
|
||||||
(let* ((items-len (1- (length dashboard-items)))
|
|
||||||
(first-item (car (nth 0 dashboard-items)))
|
|
||||||
(current (or (ignore-errors (dashboard--current-section))
|
|
||||||
first-item))
|
|
||||||
(items (mapcar #'car dashboard-items))
|
|
||||||
(find (cl-position current items :test #'equal))
|
|
||||||
(prev-index (1- find))
|
|
||||||
(prev (cond (dashboard-navigation-cycle
|
|
||||||
(if (< prev-index 0) (nth items-len items)
|
|
||||||
(nth prev-index items)))
|
|
||||||
(t
|
|
||||||
(if (< prev-index 0) (nth 0 items)
|
|
||||||
(nth prev-index items))))))
|
|
||||||
(dashboard--goto-section prev)))
|
|
||||||
|
|
||||||
(defun dashboard-next-section ()
|
|
||||||
"Navigate forward to next section."
|
|
||||||
(interactive)
|
|
||||||
(let* ((items-len (1- (length dashboard-items)))
|
|
||||||
(last-item (car (nth items-len dashboard-items)))
|
|
||||||
(current (or (ignore-errors (dashboard--current-section))
|
|
||||||
last-item))
|
|
||||||
(items (mapcar #'car dashboard-items))
|
|
||||||
(find (cl-position current items :test #'equal))
|
|
||||||
(next-index (1+ find))
|
|
||||||
(next (cond (dashboard-navigation-cycle
|
|
||||||
(or (nth next-index items)
|
|
||||||
(nth 0 items)))
|
|
||||||
(t
|
|
||||||
(if (< items-len next-index)
|
|
||||||
(nth (min items-len next-index) items)
|
|
||||||
(nth next-index items))))))
|
|
||||||
(dashboard--goto-section next)))
|
|
||||||
|
|
||||||
(defun dashboard--section-lines ()
|
|
||||||
"Return a list of integer represent the starting line number of each section."
|
|
||||||
(let (pb-lst)
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (search-forward (dashboard--separator) nil t)
|
|
||||||
(when (ignore-errors (dashboard--current-section))
|
|
||||||
(push (line-number-at-pos) pb-lst))))
|
|
||||||
(setq pb-lst (reverse pb-lst))
|
|
||||||
pb-lst))
|
|
||||||
|
|
||||||
(defun dashboard--goto-section-by-index (index)
|
|
||||||
"Navigate to item section by INDEX."
|
|
||||||
(let* ((pg-lst (dashboard--section-lines))
|
|
||||||
(items-id (1- index))
|
|
||||||
(items-pg (nth items-id pg-lst))
|
|
||||||
(items-len (length pg-lst)))
|
|
||||||
(when (and items-pg (< items-id items-len))
|
|
||||||
(dashboard--goto-line items-pg))))
|
|
||||||
|
|
||||||
(defun dashboard-section-1 ()
|
|
||||||
"Navigate to section 1." (interactive) (dashboard--goto-section-by-index 1))
|
|
||||||
(defun dashboard-section-2 ()
|
|
||||||
"Navigate to section 2." (interactive) (dashboard--goto-section-by-index 2))
|
|
||||||
(defun dashboard-section-3 ()
|
|
||||||
"Navigate to section 3." (interactive) (dashboard--goto-section-by-index 3))
|
|
||||||
(defun dashboard-section-4 ()
|
|
||||||
"Navigate to section 4." (interactive) (dashboard--goto-section-by-index 4))
|
|
||||||
(defun dashboard-section-5 ()
|
|
||||||
"Navigate to section 5." (interactive) (dashboard--goto-section-by-index 5))
|
|
||||||
(defun dashboard-section-6 ()
|
|
||||||
"Navigate to section 6." (interactive) (dashboard--goto-section-by-index 6))
|
|
||||||
(defun dashboard-section-7 ()
|
|
||||||
"Navigate to section 7." (interactive) (dashboard--goto-section-by-index 7))
|
|
||||||
(defun dashboard-section-8 ()
|
|
||||||
"Navigate to section 8." (interactive) (dashboard--goto-section-by-index 8))
|
|
||||||
(defun dashboard-section-9 ()
|
|
||||||
"Navigate to section 9." (interactive) (dashboard--goto-section-by-index 9))
|
|
||||||
|
|
||||||
(defun dashboard-previous-line (arg)
|
|
||||||
"Move point up and position it at that line’s item.
|
|
||||||
Optional prefix ARG says how many lines to move; default is one line."
|
|
||||||
(interactive "^p")
|
|
||||||
(dashboard-next-line (- arg)))
|
|
||||||
|
|
||||||
(defun dashboard-next-line (arg)
|
|
||||||
"Move point down and position it at that line’s item.
|
|
||||||
Optional prefix ARG says how many lines to move; default is one line."
|
|
||||||
;; code heavily inspired by `dired-next-line'
|
|
||||||
(interactive "^p")
|
|
||||||
(let (line-move-visual goal-column)
|
|
||||||
(line-move arg t))
|
|
||||||
;; We never want to move point into an invisible line. Dashboard doesn’t
|
|
||||||
;; use invisible text currently but when it does we’re ready!
|
|
||||||
(while (and (invisible-p (point))
|
|
||||||
(not (if (and arg (< arg 0)) (bobp) (eobp))))
|
|
||||||
(forward-char (if (and arg (< arg 0)) -1 1)))
|
|
||||||
(beginning-of-line-text))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; ffap
|
|
||||||
|
|
||||||
(defun dashboard--goto-section (section)
|
|
||||||
"Move to SECTION declares in variable `dashboard-item-shortcuts'."
|
|
||||||
(let ((fnc (intern (format "dashboard-jump-to-%s" section))))
|
|
||||||
(dashboard-funcall-fboundp fnc)))
|
|
||||||
|
|
||||||
(defun dashboard--current-index (section &optional pos)
|
|
||||||
"Return the idex by SECTION from POS."
|
|
||||||
(let (target-ln section-line)
|
|
||||||
(save-excursion
|
|
||||||
(when pos (goto-char pos))
|
|
||||||
(setq target-ln (line-number-at-pos))
|
|
||||||
(dashboard--goto-section section)
|
|
||||||
(setq section-line (line-number-at-pos)))
|
|
||||||
(- target-ln section-line)))
|
|
||||||
|
|
||||||
(defun dashboard--section-list (section)
|
|
||||||
"Return the list from SECTION."
|
|
||||||
(cl-case section
|
|
||||||
(`recents recentf-list)
|
|
||||||
(`bookmarks (bookmark-all-names))
|
|
||||||
(`projects (dashboard-projects-backend-load-projects))
|
|
||||||
(`ls-directories (dashboard-ls--dirs))
|
|
||||||
(`ls-files (dashboard-ls--files))
|
|
||||||
(t (user-error "Unknown section for search: %s" section))))
|
|
||||||
|
|
||||||
(defun dashboard--current-item-in-path ()
|
|
||||||
"Return the path from current dashboard section in path."
|
|
||||||
(let ((section (dashboard--current-section)) path)
|
|
||||||
(cl-case section
|
|
||||||
(`bookmarks (setq path (bookmark-get-filename path)))
|
|
||||||
(t
|
|
||||||
(let ((lst (dashboard--section-list section))
|
|
||||||
(index (dashboard--current-index section)))
|
|
||||||
(setq path (nth index lst)))))
|
|
||||||
path))
|
|
||||||
|
|
||||||
(defun dashboard--on-path-item-p ()
|
|
||||||
"Return non-nil if current point is on the item path from dashboard."
|
|
||||||
(save-excursion
|
|
||||||
(when (= (point) (line-end-position)) (ignore-errors (forward-char -1)))
|
|
||||||
(eq (get-char-property (point) 'face) 'dashboard-items-face)))
|
|
||||||
|
|
||||||
(defun dashboard--ffap-guesser--adv (fnc &rest args)
|
|
||||||
"Advice execution around function `ffap-guesser'.
|
|
||||||
|
|
||||||
Argument FNC is the adviced function.
|
|
||||||
Optional argument ARGS adviced function arguments."
|
|
||||||
(cl-case major-mode
|
|
||||||
(`dashboard-mode
|
|
||||||
(or (and (dashboard--on-path-item-p)
|
|
||||||
(dashboard--current-item-in-path))
|
|
||||||
(apply fnc args))) ; fallback
|
|
||||||
(t (apply fnc args))))
|
|
||||||
(advice-add 'ffap-guesser :around #'dashboard--ffap-guesser--adv)
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Removal
|
|
||||||
|
|
||||||
(defun dashboard-remove-item-under ()
|
|
||||||
"Remove a item from the current item section."
|
|
||||||
(interactive)
|
|
||||||
(cl-case (dashboard--current-section)
|
|
||||||
(`recents (dashboard-remove-item-recentf))
|
|
||||||
(`bookmarks (dashboard-remove-item-bookmarks))
|
|
||||||
(`projects (dashboard-remove-item-projects))
|
|
||||||
(`agenda (dashboard-remove-item-agenda))
|
|
||||||
(`registers (dashboard-remove-item-registers)))
|
|
||||||
(dashboard--save-excursion (dashboard-refresh-buffer)))
|
|
||||||
|
|
||||||
(defun dashboard-remove-item-recentf ()
|
|
||||||
"Remove a file from `recentf-list'."
|
|
||||||
(interactive)
|
|
||||||
(let ((path (save-excursion (end-of-line) (ffap-guesser))))
|
|
||||||
(setq recentf-list (delete path recentf-list)))
|
|
||||||
(dashboard-mute-apply (recentf-save-list)))
|
|
||||||
|
|
||||||
(defun dashboard-remove-item-projects ()
|
|
||||||
"Remove a path from `project--list'."
|
|
||||||
(interactive)
|
|
||||||
(let ((path (save-excursion (end-of-line) (ffap-guesser))))
|
|
||||||
(dashboard-mute-apply
|
|
||||||
(cl-case dashboard-projects-backend
|
|
||||||
(`projectile (projectile-remove-known-project path))
|
|
||||||
(`project-el (project-forget-projects-under path))))))
|
|
||||||
|
|
||||||
(defun dashboard-remove-item-bookmarks ()
|
|
||||||
"Remove a bookmarks from `bookmark-alist'."
|
|
||||||
(interactive)) ; TODO: ..
|
|
||||||
|
|
||||||
(defun dashboard-remove-item-agenda ()
|
|
||||||
"Remove an agenda from `org-agenda-files'."
|
|
||||||
(interactive "P")
|
|
||||||
(let ((agenda-file (get-text-property (point) 'dashboard-agenda-file))
|
|
||||||
(agenda-loc (get-text-property (point) 'dashboard-agenda-loc)))
|
|
||||||
(with-current-buffer (find-file-noselect agenda-file)
|
|
||||||
(goto-char agenda-loc)
|
|
||||||
(call-interactively 'org-todo))))
|
|
||||||
|
|
||||||
(defun dashboard-remove-item-registers ()
|
|
||||||
"Remove a registers from `register-alist'."
|
|
||||||
(interactive)) ; TODO: ..
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Confirmation
|
|
||||||
|
|
||||||
(defun dashboard-return ()
|
|
||||||
"Hit return key in dashboard buffer."
|
|
||||||
(interactive)
|
|
||||||
(let ((start-ln (line-number-at-pos)) (fd-cnt 0) diff-line entry-pt)
|
|
||||||
(save-excursion
|
|
||||||
(while (and (not diff-line)
|
|
||||||
(not (= (point) (point-min)))
|
|
||||||
(not (get-char-property (point) 'button))
|
|
||||||
(not (= (point) (point-max))))
|
|
||||||
(forward-char 1)
|
|
||||||
(setq fd-cnt (1+ fd-cnt))
|
|
||||||
(unless (= start-ln (line-number-at-pos))
|
|
||||||
(setq diff-line t)))
|
|
||||||
(unless (= (point) (point-max))
|
|
||||||
(setq entry-pt (point))))
|
|
||||||
(when (= fd-cnt 1)
|
|
||||||
(setq entry-pt (1- (point))))
|
|
||||||
(if entry-pt
|
|
||||||
(widget-button-press entry-pt)
|
|
||||||
(call-interactively #'widget-button-press))))
|
|
||||||
|
|
||||||
(defun dashboard-mouse-1 ()
|
|
||||||
"Key for keymap `mouse-1'."
|
|
||||||
(interactive)
|
|
||||||
(let ((old-track-mouse track-mouse))
|
|
||||||
(when (call-interactively #'widget-button-click)
|
|
||||||
(setq track-mouse old-track-mouse))))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Insertion
|
|
||||||
|
|
||||||
(defmacro dashboard--with-buffer (&rest body)
|
|
||||||
"Execute BODY in dashboard buffer."
|
|
||||||
(declare (indent 0))
|
|
||||||
`(with-current-buffer (get-buffer-create dashboard-buffer-name)
|
|
||||||
(let ((inhibit-read-only t)) ,@body)
|
|
||||||
(current-buffer)))
|
|
||||||
|
|
||||||
(defun dashboard-insert-items ()
|
|
||||||
"Function to insert dashboard items.
|
|
||||||
See `dashboard-item-generators' for all items available."
|
|
||||||
(let ((recentf-is-on (recentf-enabled-p))
|
|
||||||
(origial-recentf-list recentf-list))
|
|
||||||
(mapc (lambda (els)
|
|
||||||
(let* ((el (or (car-safe els) els))
|
|
||||||
(list-size
|
|
||||||
(or (cdr-safe els)
|
|
||||||
dashboard-items-default-length))
|
|
||||||
(item-generator
|
|
||||||
(cdr-safe (assoc el dashboard-item-generators))))
|
|
||||||
|
|
||||||
(insert "\n")
|
|
||||||
(push (point) dashboard--section-starts)
|
|
||||||
(funcall item-generator list-size)
|
|
||||||
(goto-char (point-max))
|
|
||||||
|
|
||||||
(when recentf-is-on
|
|
||||||
(setq recentf-list origial-recentf-list))))
|
|
||||||
dashboard-items)
|
|
||||||
|
|
||||||
(when dashboard-center-content
|
|
||||||
(dashboard-center-text
|
|
||||||
(if dashboard--section-starts
|
|
||||||
(car (last dashboard--section-starts))
|
|
||||||
(point))
|
|
||||||
(point-max)))
|
|
||||||
|
|
||||||
(save-excursion
|
|
||||||
(dolist (start dashboard--section-starts)
|
|
||||||
(goto-char start)
|
|
||||||
(insert dashboard-page-separator)))
|
|
||||||
|
|
||||||
(insert "\n")
|
|
||||||
(insert dashboard-page-separator)))
|
|
||||||
|
|
||||||
(defun dashboard-insert-startupify-lists ()
|
|
||||||
"Insert the list of widgets into the buffer."
|
|
||||||
(interactive)
|
|
||||||
(let ((inhibit-redisplay t)
|
|
||||||
(recentf-is-on (recentf-enabled-p))
|
|
||||||
(origial-recentf-list recentf-list)
|
|
||||||
(dashboard-num-recents (or (cdr (assoc 'recents dashboard-items)) 0)))
|
|
||||||
(when recentf-is-on
|
|
||||||
(setq recentf-list (dashboard-subseq recentf-list dashboard-num-recents)))
|
|
||||||
(dashboard--with-buffer
|
|
||||||
(when (or dashboard-force-refresh (not (eq major-mode 'dashboard-mode)))
|
|
||||||
(run-hooks 'dashboard-before-initialize-hook)
|
|
||||||
(erase-buffer)
|
|
||||||
(setq dashboard--section-starts nil)
|
|
||||||
|
|
||||||
(mapc (lambda (entry)
|
|
||||||
(if (and (listp entry)
|
|
||||||
(not (functionp entry)))
|
|
||||||
(apply (car entry) `(,(cdr entry)))
|
|
||||||
(funcall entry)))
|
|
||||||
dashboard-startupify-list)
|
|
||||||
|
|
||||||
(when dashboard-vertically-center-content
|
|
||||||
(goto-char (point-min))
|
|
||||||
(when-let* ((content-height (cdr (window-absolute-pixel-position (point-max))))
|
|
||||||
(vertical-padding (floor (/ (- (window-pixel-height) content-height) 2)))
|
|
||||||
((> vertical-padding 0))
|
|
||||||
(vertical-lines (1- (floor (/ vertical-padding (line-pixel-height)))))
|
|
||||||
((> vertical-lines 0)))
|
|
||||||
(insert (make-string vertical-lines ?\n))))
|
|
||||||
|
|
||||||
(goto-char (point-min))
|
|
||||||
(dashboard-mode)))
|
|
||||||
(when recentf-is-on
|
|
||||||
(setq recentf-list origial-recentf-list))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun dashboard-open (&rest _)
|
|
||||||
"Open (or refresh) the *dashboard* buffer."
|
|
||||||
(interactive)
|
|
||||||
(let ((dashboard-force-refresh t)) (dashboard-insert-startupify-lists))
|
|
||||||
(switch-to-buffer dashboard-buffer-name))
|
|
||||||
|
|
||||||
(defalias #'dashboard-refresh-buffer #'dashboard-open)
|
|
||||||
|
|
||||||
(defun dashboard-resize-on-hook (&optional _)
|
|
||||||
"Re-render dashboard on window size change."
|
|
||||||
(let ((space-win (get-buffer-window dashboard-buffer-name))
|
|
||||||
(frame-win (frame-selected-window)))
|
|
||||||
(when (and space-win
|
|
||||||
(not (window-minibuffer-p frame-win)))
|
|
||||||
(with-selected-window space-win
|
|
||||||
(dashboard-insert-startupify-lists)))))
|
|
||||||
|
|
||||||
(defun dashboard-initialize ()
|
|
||||||
"Switch to dashboard and run `dashboard-after-initialize-hook'."
|
|
||||||
(switch-to-buffer dashboard-buffer-name)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(redisplay)
|
|
||||||
(run-hooks 'dashboard-after-initialize-hook))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun dashboard-setup-startup-hook ()
|
|
||||||
"Setup post initialization hooks unless a command line argument is provided."
|
|
||||||
(when (< (length command-line-args) 2) ;; Assume no file name passed
|
|
||||||
(add-hook 'window-size-change-functions #'dashboard-resize-on-hook 100)
|
|
||||||
(add-hook 'window-setup-hook #'dashboard-resize-on-hook)
|
|
||||||
(add-hook 'after-init-hook #'dashboard-insert-startupify-lists)
|
|
||||||
(add-hook 'emacs-startup-hook #'dashboard-initialize)))
|
|
||||||
|
|
||||||
(provide 'dashboard)
|
|
||||||
;;; dashboard.el ends here
|
|
|
@ -1,6 +1,6 @@
|
||||||
(define-package "devdocs" "20240428.711" "Emacs viewer for DevDocs"
|
(define-package "devdocs" "20240301.1838" "Emacs viewer for DevDocs"
|
||||||
'((emacs "27.1"))
|
'((emacs "27.1"))
|
||||||
:commit "c14d1306648d3ae09ee3a3b3f45592334943cfeb" :authors
|
:commit "3424436f333955b39a0803ce9781aaffaae003f5" :authors
|
||||||
'(("Augusto Stoffel" . "arstoffel@gmail.com"))
|
'(("Augusto Stoffel" . "arstoffel@gmail.com"))
|
||||||
:maintainers
|
:maintainers
|
||||||
'(("Augusto Stoffel" . "arstoffel@gmail.com"))
|
'(("Augusto Stoffel" . "arstoffel@gmail.com"))
|
|
@ -1,12 +1,12 @@
|
||||||
;;; devdocs.el --- Emacs viewer for DevDocs -*- lexical-binding: t -*-
|
;;; devdocs.el --- Emacs viewer for DevDocs -*- lexical-binding: t -*-
|
||||||
|
|
||||||
;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
|
;; Copyright (C) 2021 Free Software Foundation, Inc.
|
||||||
|
|
||||||
;; Author: Augusto Stoffel <arstoffel@gmail.com>
|
;; Author: Augusto Stoffel <arstoffel@gmail.com>
|
||||||
;; Keywords: help
|
;; Keywords: help
|
||||||
;; URL: https://github.com/astoff/devdocs.el
|
;; URL: https://github.com/astoff/devdocs.el
|
||||||
;; Package-Requires: ((emacs "27.1"))
|
;; Package-Requires: ((emacs "27.1"))
|
||||||
;; Version: 0.6.1
|
;; Version: 0.5
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
;; This program is free software; you can redistribute it and/or modify
|
||||||
;; it under the terms of the GNU General Public License as published by
|
;; it under the terms of the GNU General Public License as published by
|
||||||
|
@ -82,7 +82,7 @@ name and a count."
|
||||||
:type '(choice (const :tag "Count in parentheses, italicized"
|
:type '(choice (const :tag "Count in parentheses, italicized"
|
||||||
#("%s (%s)" 3 7 (face italic)))
|
#("%s (%s)" 3 7 (face italic)))
|
||||||
(const :tag "Invisible cookie"
|
(const :tag "Invisible cookie"
|
||||||
#("%s#%s" 2 5 (invisible t)))
|
#("%s (%s)" 2 7 (invisible t)))
|
||||||
string))
|
string))
|
||||||
|
|
||||||
(defcustom devdocs-fontify-code-blocks t
|
(defcustom devdocs-fontify-code-blocks t
|
||||||
|
@ -94,9 +94,6 @@ Fontification is done using the `org-src' library, which see."
|
||||||
"Whether to select the DevDocs window for viewing."
|
"Whether to select the DevDocs window for viewing."
|
||||||
:type 'boolean)
|
:type 'boolean)
|
||||||
|
|
||||||
(defvar devdocs-extra-rendering-functions '()
|
|
||||||
"Extra functions for `shr-external-rendering-functions'.")
|
|
||||||
|
|
||||||
(defface devdocs-code-block '((t nil))
|
(defface devdocs-code-block '((t nil))
|
||||||
"Additional face to apply to code blocks in DevDocs buffers.")
|
"Additional face to apply to code blocks in DevDocs buffers.")
|
||||||
|
|
||||||
|
@ -319,10 +316,7 @@ already installed, reinstall it."
|
||||||
"Go to the original position in a DevDocs buffer."
|
"Go to the original position in a DevDocs buffer."
|
||||||
(interactive)
|
(interactive)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(when-let ((frag (let-alist (car devdocs--stack)
|
(when-let ((pred (if (fboundp 'shr--set-target-ids) #'member t)) ;; shr change in Emacs 29
|
||||||
(or .fragment (devdocs--path-fragment .path))))
|
|
||||||
(shr-target-id (url-unhex-string frag))
|
|
||||||
(pred (if (fboundp 'shr--set-target-ids) #'member t)) ;; shr change in Emacs 29
|
|
||||||
(match (text-property-search-forward 'shr-target-id shr-target-id pred)))
|
(match (text-property-search-forward 'shr-target-id shr-target-id pred)))
|
||||||
(goto-char (prop-match-beginning match))))
|
(goto-char (prop-match-beginning match))))
|
||||||
|
|
||||||
|
@ -483,18 +477,15 @@ fragment part of ENTRY.path."
|
||||||
(unless (eq major-mode 'devdocs-mode)
|
(unless (eq major-mode 'devdocs-mode)
|
||||||
(devdocs-mode))
|
(devdocs-mode))
|
||||||
(let-alist entry
|
(let-alist entry
|
||||||
(let* ((inhibit-read-only t)
|
(let ((inhibit-read-only t)
|
||||||
(extra-rendering-functions (cdr (assoc
|
(shr-external-rendering-functions `((pre . devdocs--shr-tag-pre)
|
||||||
(intern .doc.type)
|
,@shr-external-rendering-functions))
|
||||||
devdocs-extra-rendering-functions)))
|
(file (expand-file-name (format "%s/%s.html"
|
||||||
(shr-external-rendering-functions `((pre . devdocs--shr-tag-pre)
|
.doc.slug
|
||||||
,@extra-rendering-functions
|
(url-hexify-string (devdocs--path-file .path)))
|
||||||
,@shr-external-rendering-functions))
|
devdocs-data-dir)))
|
||||||
(file (expand-file-name (format "%s/%s.html"
|
|
||||||
.doc.slug
|
|
||||||
(url-hexify-string (devdocs--path-file .path)))
|
|
||||||
devdocs-data-dir)))
|
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
|
(setq-local shr-target-id (url-unhex-string (or .fragment (devdocs--path-fragment .path))))
|
||||||
;; TODO: cl-progv here for shr settings?
|
;; TODO: cl-progv here for shr settings?
|
||||||
(shr-insert-document
|
(shr-insert-document
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
|
@ -503,9 +494,7 @@ fragment part of ENTRY.path."
|
||||||
(set-buffer-modified-p nil)
|
(set-buffer-modified-p nil)
|
||||||
(setq-local devdocs-current-docs (list .doc.slug))
|
(setq-local devdocs-current-docs (list .doc.slug))
|
||||||
(push entry devdocs--stack)
|
(push entry devdocs--stack)
|
||||||
(setq-local list-buffers-directory (format-mode-line devdocs-header-line
|
(setq-local list-buffers-directory (format-mode-line devdocs-header-line nil nil (current-buffer)))
|
||||||
nil nil
|
|
||||||
(current-buffer)))
|
|
||||||
(devdocs-goto-target)
|
(devdocs-goto-target)
|
||||||
(current-buffer))))
|
(current-buffer))))
|
||||||
|
|
|
@ -1,648 +0,0 @@
|
||||||
;;; devdocs.el --- Emacs viewer for DevDocs -*- lexical-binding: t -*-
|
|
||||||
|
|
||||||
;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
;; Author: Augusto Stoffel <arstoffel@gmail.com>
|
|
||||||
;; Keywords: help
|
|
||||||
;; URL: https://github.com/astoff/devdocs.el
|
|
||||||
;; Package-Requires: ((emacs "27.1"))
|
|
||||||
;; Version: 0.6.1
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
|
||||||
;; it under the terms of the GNU General Public License as published by
|
|
||||||
;; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
|
|
||||||
;; This program is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
;; GNU General Public License for more details.
|
|
||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; devdocs.el is a documentation viewer similar to the built-in Info
|
|
||||||
;; browser, but geared towards documentation obtained from
|
|
||||||
;; https://devdocs.io.
|
|
||||||
|
|
||||||
;; To get started, download some documentation with `devdocs-install`.
|
|
||||||
;; This will show the available documents and save the selected one to
|
|
||||||
;; disk. Once you have the desired documents at hand, use
|
|
||||||
;; `devdocs-lookup` to search for entries.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'seq)
|
|
||||||
(require 'shr)
|
|
||||||
(require 'url-expand)
|
|
||||||
(eval-when-compile
|
|
||||||
(require 'let-alist)
|
|
||||||
(require 'subr-x))
|
|
||||||
|
|
||||||
(unless (libxml-available-p)
|
|
||||||
(display-warning 'devdocs "This package requires Emacs to be compiled with libxml2"))
|
|
||||||
|
|
||||||
(defgroup devdocs nil
|
|
||||||
"Emacs viewer for DevDocs."
|
|
||||||
:group 'help
|
|
||||||
:prefix "devdocs-")
|
|
||||||
|
|
||||||
(defcustom devdocs-current-docs nil
|
|
||||||
"A list of documents relevant to the current buffer.
|
|
||||||
This variable is normally set by the `devdocs-lookup' command,
|
|
||||||
but you may also wish to set it via a hook or as file or
|
|
||||||
directory-local variable."
|
|
||||||
:local t
|
|
||||||
:type '(list string))
|
|
||||||
|
|
||||||
(defcustom devdocs-data-dir (expand-file-name "devdocs" user-emacs-directory)
|
|
||||||
"Directory to save documentation files."
|
|
||||||
:type 'directory)
|
|
||||||
|
|
||||||
(defvar devdocs-site-url "https://devdocs.io"
|
|
||||||
"Location of the DevDocs website.")
|
|
||||||
|
|
||||||
(defvar devdocs-cdn-url "https://documents.devdocs.io"
|
|
||||||
"Location of the DevDocs CDN.")
|
|
||||||
|
|
||||||
(defcustom devdocs-cache-timeout 900
|
|
||||||
"Number of seconds to keep cached information such as document indexes."
|
|
||||||
:type 'number)
|
|
||||||
|
|
||||||
(defcustom devdocs-separator " » "
|
|
||||||
"String used to format a documentation location, e.g. in header line."
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom devdocs-disambiguated-entry-format #("%s (%s)" 3 7 (face italic))
|
|
||||||
"How to disambiguate entries with identical names in `devdocs-lookup'.
|
|
||||||
This string is passed to `format' with two arguments, the entry
|
|
||||||
name and a count."
|
|
||||||
:type '(choice (const :tag "Count in parentheses, italicized"
|
|
||||||
#("%s (%s)" 3 7 (face italic)))
|
|
||||||
(const :tag "Invisible cookie"
|
|
||||||
#("%s#%s" 2 5 (invisible t)))
|
|
||||||
string))
|
|
||||||
|
|
||||||
(defcustom devdocs-fontify-code-blocks t
|
|
||||||
"Whether to fontify code snippets inside pre tags.
|
|
||||||
Fontification is done using the `org-src' library, which see."
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom devdocs-window-select nil
|
|
||||||
"Whether to select the DevDocs window for viewing."
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defvar devdocs-extra-rendering-functions '()
|
|
||||||
"Extra functions for `shr-external-rendering-functions'.")
|
|
||||||
|
|
||||||
(defface devdocs-code-block '((t nil))
|
|
||||||
"Additional face to apply to code blocks in DevDocs buffers.")
|
|
||||||
|
|
||||||
(defvar devdocs-history nil
|
|
||||||
"History of documentation entries.")
|
|
||||||
|
|
||||||
(defconst devdocs--data-format-version 1
|
|
||||||
"Version number of the saved documentation data format.")
|
|
||||||
|
|
||||||
;;; Memoization
|
|
||||||
|
|
||||||
(defvar devdocs--cache (make-hash-table :test 'equal)
|
|
||||||
"Hash table used by `devdocs--with-cache'.")
|
|
||||||
|
|
||||||
(defmacro devdocs--with-cache (&rest body)
|
|
||||||
"Evaluate BODY with memoization.
|
|
||||||
The return value is stored and reused if needed again within the
|
|
||||||
time span specified by `devdocs-cache-timeout'.
|
|
||||||
|
|
||||||
Note that the lexical environment is used to associate BODY to
|
|
||||||
its return value; take the necessary precautions."
|
|
||||||
`(if-let ((fun (lambda () ,@body))
|
|
||||||
(funrep ,(if (< emacs-major-version 28) ;; Cf. bug#32503
|
|
||||||
'(prin1-to-string fun)
|
|
||||||
'fun))
|
|
||||||
(data (gethash funrep devdocs--cache)))
|
|
||||||
(prog1 (cdr data)
|
|
||||||
(timer-set-time (car data) (time-add nil devdocs-cache-timeout)))
|
|
||||||
(let ((val (funcall fun))
|
|
||||||
(timer (run-at-time devdocs-cache-timeout nil
|
|
||||||
#'remhash funrep devdocs--cache)))
|
|
||||||
(prog1 val
|
|
||||||
(puthash funrep (cons timer val) devdocs--cache)))))
|
|
||||||
|
|
||||||
;;; Documentation management
|
|
||||||
|
|
||||||
(defalias 'devdocs--json-parse-buffer
|
|
||||||
(if (json-available-p)
|
|
||||||
(lambda () (json-parse-buffer :object-type 'alist))
|
|
||||||
(require 'json)
|
|
||||||
#'json-read))
|
|
||||||
|
|
||||||
(defun devdocs--doc-metadata (slug)
|
|
||||||
"Return the metadata of an installed document named SLUG."
|
|
||||||
(let ((file (expand-file-name (concat slug "/metadata") devdocs-data-dir)))
|
|
||||||
(unless (file-exists-p file)
|
|
||||||
(user-error "Document `%s' is not installed" slug))
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents file)
|
|
||||||
(let ((metadata (read (current-buffer))))
|
|
||||||
(unless (eq (car metadata) devdocs--data-format-version)
|
|
||||||
(user-error "Please run `devdocs-update-all'"))
|
|
||||||
(cdr metadata)))))
|
|
||||||
|
|
||||||
(defun devdocs--installed-docs ()
|
|
||||||
"Return a list of installed documents."
|
|
||||||
(mapcar #'devdocs--doc-metadata
|
|
||||||
(let ((default-directory devdocs-data-dir))
|
|
||||||
(seq-filter #'file-directory-p
|
|
||||||
(when (file-directory-p devdocs-data-dir)
|
|
||||||
(directory-files "." nil "^[^.]"))))))
|
|
||||||
|
|
||||||
(defun devdocs--available-docs ()
|
|
||||||
"Return a list of available documents.
|
|
||||||
If necessary, download data from `devdocs-site-url'."
|
|
||||||
(devdocs--with-cache
|
|
||||||
(with-temp-buffer
|
|
||||||
(url-insert-file-contents
|
|
||||||
(format "%s/docs.json" devdocs-site-url))
|
|
||||||
(devdocs--json-parse-buffer))))
|
|
||||||
|
|
||||||
(defun devdocs--doc-title (doc)
|
|
||||||
"Title of document DOC.
|
|
||||||
DOC is either a metadata alist, or the slug of an installed
|
|
||||||
document."
|
|
||||||
(let-alist (if (stringp doc) (devdocs--doc-metadata doc) doc)
|
|
||||||
(if (seq-empty-p .version) .name (concat .name " " .version))))
|
|
||||||
|
|
||||||
(defun devdocs--read-document (prompt &optional multiple available)
|
|
||||||
"Query interactively for a DevDocs document.
|
|
||||||
|
|
||||||
PROMPT is passed to `completing-read'.
|
|
||||||
Non-nil MULTIPLE allows selecting multiple documents.
|
|
||||||
Non-nil AVAILABLE means to offer a list of all available documents;
|
|
||||||
otherwise, offer only installed documents.
|
|
||||||
|
|
||||||
Return a document metadata alist if MULTIPLE is nil; otherwise, a
|
|
||||||
list of metadata alists."
|
|
||||||
(let ((cands (mapcar (lambda (it) (cons (alist-get 'slug it) it))
|
|
||||||
(if available
|
|
||||||
(devdocs--available-docs)
|
|
||||||
(or (devdocs--installed-docs)
|
|
||||||
(user-error "No documents in `%s'" devdocs-data-dir))))))
|
|
||||||
(if multiple
|
|
||||||
(delq nil (mapcar (lambda (s) (cdr (assoc s cands)))
|
|
||||||
(completing-read-multiple prompt cands)))
|
|
||||||
(cdr (assoc (completing-read prompt cands nil t) cands)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-delete (doc)
|
|
||||||
"Delete DevDocs documentation.
|
|
||||||
DOC is a document metadata alist."
|
|
||||||
(interactive (list (devdocs--read-document "Delete documentation: ")))
|
|
||||||
(let ((dest (expand-file-name (alist-get 'slug doc) devdocs-data-dir)))
|
|
||||||
(if (and (file-directory-p dest)
|
|
||||||
(file-in-directory-p dest devdocs-data-dir))
|
|
||||||
(delete-directory dest t)
|
|
||||||
(user-error "Document `%s' is not installed" (alist-get 'slug doc)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-install (doc)
|
|
||||||
"Download and install DevDocs documentation.
|
|
||||||
DOC is a document slug or metadata alist. If the document is
|
|
||||||
already installed, reinstall it."
|
|
||||||
(interactive (list (devdocs--read-document "Install documentation: " nil t)))
|
|
||||||
(make-directory devdocs-data-dir t)
|
|
||||||
(unless (listp doc)
|
|
||||||
(setq doc (or (seq-find (lambda (it) (string= doc (alist-get 'slug it)))
|
|
||||||
(devdocs--available-docs))
|
|
||||||
(user-error "No such document: %s" doc))))
|
|
||||||
(let* ((slug (alist-get 'slug doc))
|
|
||||||
(mtime (alist-get 'mtime doc))
|
|
||||||
(temp (make-temp-file "devdocs-" t))
|
|
||||||
pages)
|
|
||||||
(with-temp-buffer
|
|
||||||
(url-insert-file-contents (format "%s/%s/db.json?%s" devdocs-cdn-url slug mtime))
|
|
||||||
(dolist-with-progress-reporter
|
|
||||||
(entry (devdocs--json-parse-buffer))
|
|
||||||
"Installing documentation..."
|
|
||||||
(with-temp-file (expand-file-name
|
|
||||||
(url-hexify-string (format "%s.html" (car entry))) temp)
|
|
||||||
(push (symbol-name (car entry)) pages)
|
|
||||||
(insert (cdr entry)))))
|
|
||||||
(with-temp-buffer
|
|
||||||
(url-insert-file-contents (format "%s/%s/index.json?%s" devdocs-cdn-url slug mtime))
|
|
||||||
(let ((index (devdocs--json-parse-buffer)))
|
|
||||||
(push `(pages . ,(vconcat (nreverse pages))) index)
|
|
||||||
(with-temp-file (expand-file-name "index" temp)
|
|
||||||
(prin1 index (current-buffer)))))
|
|
||||||
(with-temp-file (expand-file-name "metadata" temp)
|
|
||||||
(prin1 (cons devdocs--data-format-version doc) (current-buffer)))
|
|
||||||
(let ((dest (expand-file-name slug devdocs-data-dir)))
|
|
||||||
(when (and (file-directory-p dest)
|
|
||||||
(file-in-directory-p dest devdocs-data-dir))
|
|
||||||
(delete-directory dest t))
|
|
||||||
(rename-file (file-name-as-directory temp) dest))
|
|
||||||
(message "Document `%s' installed" slug)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-update-all ()
|
|
||||||
"Reinstall all documents with a new version available."
|
|
||||||
(interactive)
|
|
||||||
(when-let ((installed (when (file-directory-p devdocs-data-dir)
|
|
||||||
(directory-files devdocs-data-dir nil "^[^.]")))
|
|
||||||
(newer (seq-filter
|
|
||||||
(lambda (doc)
|
|
||||||
(let-alist doc
|
|
||||||
(and (member .slug installed)
|
|
||||||
(< (alist-get 'mtime
|
|
||||||
(ignore-errors (devdocs--doc-metadata .slug))
|
|
||||||
0) ;; Update docs with an old data format too
|
|
||||||
.mtime))))
|
|
||||||
(devdocs--available-docs)))
|
|
||||||
((y-or-n-p (format "Update %s documents %s?"
|
|
||||||
(length newer)
|
|
||||||
(mapcar (lambda (d) (alist-get 'slug d)) newer)))))
|
|
||||||
(dolist (doc newer)
|
|
||||||
(devdocs-install doc))))
|
|
||||||
|
|
||||||
;;; Document indexes
|
|
||||||
|
|
||||||
(defun devdocs--index (doc kind)
|
|
||||||
"Return an index of document DOC, where KIND is `entries', `pages' or `types'."
|
|
||||||
(if kind
|
|
||||||
(alist-get kind (devdocs--with-cache (devdocs--index doc nil)))
|
|
||||||
(let* ((docmeta (cons 'doc doc))
|
|
||||||
(indexes (with-temp-buffer
|
|
||||||
(insert-file-contents (expand-file-name
|
|
||||||
(concat (alist-get 'slug doc) "/index")
|
|
||||||
devdocs-data-dir))
|
|
||||||
(read (current-buffer))))
|
|
||||||
(entries (alist-get 'entries indexes)))
|
|
||||||
(prog1 indexes
|
|
||||||
(seq-do-indexed (lambda (entry i) (aset entries i (cons docmeta entry)))
|
|
||||||
entries)))))
|
|
||||||
|
|
||||||
;;; Documentation viewer
|
|
||||||
|
|
||||||
(defvar-local devdocs--stack nil
|
|
||||||
"List of viewed entries, set buffer-locally when in `devdocs-mode'.")
|
|
||||||
|
|
||||||
(defvar-local devdocs--forward-stack nil
|
|
||||||
"List of viewed entries for `devdocs-go-forward'.")
|
|
||||||
|
|
||||||
(defvar devdocs-header-line
|
|
||||||
'(:eval (let-alist (car devdocs--stack)
|
|
||||||
(concat (devdocs--doc-title .doc)
|
|
||||||
(and .type devdocs-separator) .type
|
|
||||||
devdocs-separator (or .name .path)))))
|
|
||||||
|
|
||||||
(define-derived-mode devdocs-mode special-mode "DevDocs"
|
|
||||||
"Major mode for viewing DevDocs documents."
|
|
||||||
:interactive nil
|
|
||||||
(if (boundp 'browse-url-handlers) ;; Emacs ≥ 28
|
|
||||||
(setq-local browse-url-handlers
|
|
||||||
`((devdocs--internal-url-p . devdocs--internal-url-handler)
|
|
||||||
,@browse-url-handlers))
|
|
||||||
(setq-local browse-url-browser-function
|
|
||||||
`(("\\`[^:]+\\'" . devdocs--internal-url-handler)
|
|
||||||
,@(if (functionp browse-url-browser-function)
|
|
||||||
`(("" . ,browse-url-browser-function))
|
|
||||||
browse-url-browser-function))))
|
|
||||||
(setq-local
|
|
||||||
buffer-undo-list t
|
|
||||||
header-line-format devdocs-header-line
|
|
||||||
revert-buffer-function #'devdocs--revert-buffer
|
|
||||||
truncate-lines t))
|
|
||||||
|
|
||||||
(defun devdocs-goto-target ()
|
|
||||||
"Go to the original position in a DevDocs buffer."
|
|
||||||
(interactive)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(when-let ((frag (let-alist (car devdocs--stack)
|
|
||||||
(or .fragment (devdocs--path-fragment .path))))
|
|
||||||
(shr-target-id (url-unhex-string frag))
|
|
||||||
(pred (if (fboundp 'shr--set-target-ids) #'member t)) ;; shr change in Emacs 29
|
|
||||||
(match (text-property-search-forward 'shr-target-id shr-target-id pred)))
|
|
||||||
(goto-char (prop-match-beginning match))))
|
|
||||||
|
|
||||||
(defun devdocs-go-back ()
|
|
||||||
"Go to the previously displayed entry in this DevDocs buffer."
|
|
||||||
(interactive)
|
|
||||||
(unless (cadr devdocs--stack)
|
|
||||||
(user-error "No previous entry"))
|
|
||||||
(push (pop devdocs--stack) devdocs--forward-stack)
|
|
||||||
(devdocs--render (pop devdocs--stack)))
|
|
||||||
|
|
||||||
(defun devdocs-go-forward ()
|
|
||||||
"Go to the next entry in this DevDocs buffer."
|
|
||||||
(interactive)
|
|
||||||
(unless (car devdocs--forward-stack)
|
|
||||||
(user-error "No next entry"))
|
|
||||||
(devdocs--render (pop devdocs--forward-stack)))
|
|
||||||
|
|
||||||
(defun devdocs-next-entry (count)
|
|
||||||
"Go forward COUNT entries in this document.
|
|
||||||
|
|
||||||
Note that this refers to the index order, which may not coincide
|
|
||||||
with the order of appearance in the text."
|
|
||||||
(interactive "p")
|
|
||||||
(let-alist (car devdocs--stack)
|
|
||||||
(let* ((entries (devdocs--index .doc 'entries))
|
|
||||||
(pred (lambda (entry _) (string= (alist-get 'path entry) .path)))
|
|
||||||
(current (seq-position entries nil pred)))
|
|
||||||
(unless current (user-error "No current entry"))
|
|
||||||
(devdocs--render
|
|
||||||
(or (ignore-error args-out-of-range (elt entries (+ count current)))
|
|
||||||
(user-error "No %s entry" (if (< count 0) "previous" "next")))))))
|
|
||||||
|
|
||||||
(defun devdocs-previous-entry (count)
|
|
||||||
"Go backward COUNT entries in this document."
|
|
||||||
(interactive "p")
|
|
||||||
(devdocs-next-entry (- count)))
|
|
||||||
|
|
||||||
(defun devdocs-goto-page (doc page)
|
|
||||||
"Go to a given PAGE (a number or path) of DOC.
|
|
||||||
Interactively, read a page name with completion."
|
|
||||||
(interactive (let-alist (car devdocs--stack)
|
|
||||||
(list .doc (completing-read "Go to page: "
|
|
||||||
(append (devdocs--index .doc 'pages) nil)
|
|
||||||
nil t nil 'devdocs-history))))
|
|
||||||
(let* ((path (cond ((stringp page) page)
|
|
||||||
((numberp page) (elt (devdocs--index doc 'pages) page))))
|
|
||||||
(entry (or (seq-find (lambda (entry) (string= (alist-get 'path entry) path))
|
|
||||||
(devdocs--index doc 'entries))
|
|
||||||
`((doc . ,doc) (path . ,path)))))
|
|
||||||
(devdocs--render entry)))
|
|
||||||
|
|
||||||
(defun devdocs-first-page (doc)
|
|
||||||
"Go to first page of DOC."
|
|
||||||
(interactive (list (alist-get 'doc (car devdocs--stack))))
|
|
||||||
(devdocs-goto-page doc 0))
|
|
||||||
|
|
||||||
(defun devdocs-last-page (doc)
|
|
||||||
"Go to last page of DOC."
|
|
||||||
(interactive (list (alist-get 'doc (car devdocs--stack))))
|
|
||||||
(devdocs-goto-page doc (1- (length (devdocs--index doc 'pages)))))
|
|
||||||
|
|
||||||
(defun devdocs-next-page (count)
|
|
||||||
"Go forward COUNT pages in this document."
|
|
||||||
(interactive "p")
|
|
||||||
(let-alist (car devdocs--stack)
|
|
||||||
(let* ((pages (devdocs--index .doc 'pages))
|
|
||||||
(dest (+ count (seq-position pages (devdocs--path-file .path)))))
|
|
||||||
(cond ((< dest 0) (user-error "No previous page"))
|
|
||||||
((<= (length pages) dest) (user-error "No next page")))
|
|
||||||
(devdocs-goto-page .doc dest))))
|
|
||||||
|
|
||||||
(defun devdocs-previous-page (count)
|
|
||||||
"Go backward COUNT entries in this document."
|
|
||||||
(interactive "p")
|
|
||||||
(devdocs-next-page (- count)))
|
|
||||||
|
|
||||||
(defun devdocs-copy-url ()
|
|
||||||
"Copy the URL of the current DevDocs page to the kill ring."
|
|
||||||
(interactive)
|
|
||||||
(let-alist (or (car devdocs--stack)
|
|
||||||
(user-error "Not in a DevDocs buffer"))
|
|
||||||
(let ((url (url-encode-url
|
|
||||||
(format "%s/%s/%s"
|
|
||||||
devdocs-site-url
|
|
||||||
.doc.slug
|
|
||||||
(if .fragment
|
|
||||||
(concat (devdocs--path-file .path) "#" .fragment)
|
|
||||||
.path)))))
|
|
||||||
(kill-new url)
|
|
||||||
(message "Copied %s" url))))
|
|
||||||
|
|
||||||
(let ((map devdocs-mode-map))
|
|
||||||
(define-key map [tab] #'forward-button)
|
|
||||||
(define-key map [backtab] #'backward-button)
|
|
||||||
(define-key map "d" #'devdocs-peruse)
|
|
||||||
(define-key map "i" #'devdocs-lookup)
|
|
||||||
(define-key map "p" #'devdocs-previous-entry)
|
|
||||||
(define-key map "n" #'devdocs-next-entry)
|
|
||||||
(define-key map "g" #'devdocs-goto-page)
|
|
||||||
(define-key map "[" #'devdocs-previous-page)
|
|
||||||
(define-key map "]" #'devdocs-next-page)
|
|
||||||
(define-key map "<" #'devdocs-first-page)
|
|
||||||
(define-key map ">" #'devdocs-last-page)
|
|
||||||
(define-key map "l" #'devdocs-go-back)
|
|
||||||
(define-key map "r" #'devdocs-go-forward)
|
|
||||||
(define-key map "w" #'devdocs-copy-url)
|
|
||||||
(define-key map "." #'devdocs-goto-target))
|
|
||||||
|
|
||||||
;;; Rendering
|
|
||||||
|
|
||||||
(defun devdocs--path-file (path)
|
|
||||||
"Return the non-fragment part of PATH."
|
|
||||||
(substring path 0 (string-match "#" path)))
|
|
||||||
|
|
||||||
(defun devdocs--path-fragment (path)
|
|
||||||
"Return the fragment part of PATH, or nil if absent."
|
|
||||||
(when-let ((i (string-match "#" path)))
|
|
||||||
(substring path (1+ i))))
|
|
||||||
|
|
||||||
(defun devdocs--path-expand (path base)
|
|
||||||
"Expand PATH relative to a BASE path."
|
|
||||||
(pcase (string-to-char path)
|
|
||||||
('?/ path)
|
|
||||||
('?# (concat (devdocs--path-file base) path))
|
|
||||||
(_ (string-remove-prefix
|
|
||||||
"/"
|
|
||||||
(url-expander-remove-relative-links ;; undocumented function!
|
|
||||||
(concat (file-name-directory base) path))))))
|
|
||||||
|
|
||||||
(defun devdocs--shr-tag-pre (dom)
|
|
||||||
"Insert and fontify pre-tag represented by DOM."
|
|
||||||
(let ((start (point)))
|
|
||||||
(if-let ((lang (and devdocs-fontify-code-blocks
|
|
||||||
(dom-attr dom 'data-language)))
|
|
||||||
(mode (or (cdr (assoc lang '(("cpp" . c++-mode)
|
|
||||||
("shell" . sh-mode))))
|
|
||||||
(intern (concat lang "-mode"))))
|
|
||||||
(buffer (and (fboundp mode) (current-buffer))))
|
|
||||||
(insert
|
|
||||||
(with-temp-buffer
|
|
||||||
(shr-tag-pre dom)
|
|
||||||
(let ((inhibit-message t)
|
|
||||||
(message-log-max nil))
|
|
||||||
(ignore-errors (delay-mode-hooks (funcall mode)))
|
|
||||||
(font-lock-ensure))
|
|
||||||
(buffer-string)))
|
|
||||||
(shr-tag-pre dom))
|
|
||||||
(add-face-text-property start (point) 'devdocs-code-block t)))
|
|
||||||
|
|
||||||
(defun devdocs--render (entry)
|
|
||||||
"Render a DevDocs documentation entry, returning a buffer.
|
|
||||||
|
|
||||||
ENTRY is an alist like those in the entry index of the document,
|
|
||||||
possibly with an additional ENTRY.fragment which overrides the
|
|
||||||
fragment part of ENTRY.path."
|
|
||||||
(with-current-buffer (get-buffer-create "*devdocs*")
|
|
||||||
(unless (eq major-mode 'devdocs-mode)
|
|
||||||
(devdocs-mode))
|
|
||||||
(let-alist entry
|
|
||||||
(let* ((inhibit-read-only t)
|
|
||||||
(extra-rendering-functions (cdr (assoc
|
|
||||||
(intern .doc.type)
|
|
||||||
devdocs-extra-rendering-functions)))
|
|
||||||
(shr-external-rendering-functions `((pre . devdocs--shr-tag-pre)
|
|
||||||
,@extra-rendering-functions
|
|
||||||
,@shr-external-rendering-functions))
|
|
||||||
(file (expand-file-name (format "%s/%s.html"
|
|
||||||
.doc.slug
|
|
||||||
(url-hexify-string (devdocs--path-file .path)))
|
|
||||||
devdocs-data-dir)))
|
|
||||||
(erase-buffer)
|
|
||||||
;; TODO: cl-progv here for shr settings?
|
|
||||||
(shr-insert-document
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents file)
|
|
||||||
(libxml-parse-html-region (point-min) (point-max)))))
|
|
||||||
(set-buffer-modified-p nil)
|
|
||||||
(setq-local devdocs-current-docs (list .doc.slug))
|
|
||||||
(push entry devdocs--stack)
|
|
||||||
(setq-local list-buffers-directory (format-mode-line devdocs-header-line
|
|
||||||
nil nil
|
|
||||||
(current-buffer)))
|
|
||||||
(devdocs-goto-target)
|
|
||||||
(current-buffer))))
|
|
||||||
|
|
||||||
(defun devdocs--revert-buffer (&rest _args)
|
|
||||||
"Refresh DevDocs buffer."
|
|
||||||
(devdocs--render (pop devdocs--stack)))
|
|
||||||
|
|
||||||
(defun devdocs--internal-url-p (url)
|
|
||||||
"Return t if URL seems to be an internal DevDocs link."
|
|
||||||
(not (string-match-p "\\`[a-z]+:" url)))
|
|
||||||
|
|
||||||
(defun devdocs--internal-url-handler (url &rest _)
|
|
||||||
"Open URL of an internal link in a DevDocs document."
|
|
||||||
(let-alist (car devdocs--stack)
|
|
||||||
(let* ((dest (devdocs--path-expand url .path))
|
|
||||||
(file (devdocs--path-file dest))
|
|
||||||
(frag (devdocs--path-fragment dest))
|
|
||||||
(entry (seq-find (lambda (it)
|
|
||||||
(let-alist it
|
|
||||||
(or (string= .path dest)
|
|
||||||
(string= .path file))))
|
|
||||||
(devdocs--index .doc 'entries))))
|
|
||||||
(unless entry (error "Can't find `%s'" dest))
|
|
||||||
(when frag (push `(fragment . ,frag) entry))
|
|
||||||
(devdocs--render entry))))
|
|
||||||
|
|
||||||
;;; Lookup commands
|
|
||||||
|
|
||||||
(defun devdocs--entries (documents)
|
|
||||||
"A list of entries in DOCUMENTS, as propertized strings."
|
|
||||||
(let* ((counts (make-hash-table :test 'equal))
|
|
||||||
(mkentry (lambda (it)
|
|
||||||
(let* ((name (alist-get 'name it))
|
|
||||||
(count (1+ (gethash name counts 0))))
|
|
||||||
(puthash name count counts)
|
|
||||||
`(,name ,count . ,it))))
|
|
||||||
(entries (mapcan (lambda (doc)
|
|
||||||
(mapcar mkentry
|
|
||||||
(devdocs--index doc 'entries)))
|
|
||||||
documents)))
|
|
||||||
(mapcar (pcase-lambda (`(,name ,count . ,it))
|
|
||||||
(propertize (if (= 1 (gethash name counts))
|
|
||||||
name
|
|
||||||
(format devdocs-disambiguated-entry-format name count))
|
|
||||||
'devdocs--data it))
|
|
||||||
entries)))
|
|
||||||
|
|
||||||
(defun devdocs--get-data (str)
|
|
||||||
"Get data stored as a string property in STR."
|
|
||||||
(get-text-property 0 'devdocs--data str))
|
|
||||||
|
|
||||||
(defun devdocs--annotate (cand)
|
|
||||||
"Return an annotation for `devdocs--read-entry' candidate CAND."
|
|
||||||
(let-alist (devdocs--get-data cand)
|
|
||||||
(concat " " (propertize " " 'display '(space :align-to 40))
|
|
||||||
(devdocs--doc-title .doc) devdocs-separator .type)))
|
|
||||||
|
|
||||||
(defun devdocs--relevant-docs (ask)
|
|
||||||
"Return a list of relevant documents for the current buffer.
|
|
||||||
May ask interactively for the desired documents, remembering the
|
|
||||||
choice for this buffer. If ASK is non-nil, ask unconditionally."
|
|
||||||
(if ask
|
|
||||||
(let ((docs (devdocs--read-document "Documents for this buffer: " t)))
|
|
||||||
(prog1 docs
|
|
||||||
(setq-local devdocs-current-docs
|
|
||||||
(mapcar (lambda (d) (alist-get 'slug d)) docs))))
|
|
||||||
(or (mapcar #'devdocs--doc-metadata devdocs-current-docs)
|
|
||||||
(devdocs--relevant-docs t)
|
|
||||||
(user-error "No documents"))))
|
|
||||||
|
|
||||||
(defun devdocs--read-entry (prompt documents initial-input)
|
|
||||||
"Read the name of an entry in one of the DOCUMENTS, using PROMPT.
|
|
||||||
|
|
||||||
INITIAL-INPUT is passed to `completing-read'"
|
|
||||||
(let* ((cands (devdocs--with-cache
|
|
||||||
(devdocs--entries documents)))
|
|
||||||
(metadata '(metadata
|
|
||||||
(category . devdocs)
|
|
||||||
(annotation-function . devdocs--annotate)))
|
|
||||||
(coll (lambda (string predicate action)
|
|
||||||
(if (eq action 'metadata)
|
|
||||||
metadata
|
|
||||||
(complete-with-action action cands string predicate))))
|
|
||||||
(cand (completing-read prompt coll nil t initial-input
|
|
||||||
'devdocs-history
|
|
||||||
(thing-at-point 'symbol))))
|
|
||||||
(devdocs--get-data (or (car (member cand cands))
|
|
||||||
(user-error "Not an entry!")))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-lookup (&optional ask-docs initial-input)
|
|
||||||
"Look up a DevDocs documentation entry.
|
|
||||||
|
|
||||||
Display entries in the documents `devdocs-current-docs' for
|
|
||||||
selection. With a prefix argument (or, from Lisp, if ASK-DOCS is
|
|
||||||
non-nil), first read the name of one or more installed documents
|
|
||||||
and set `devdocs-current-docs' for this buffer.
|
|
||||||
|
|
||||||
If INITIAL-INPUT is not nil, insert it into the minibuffer."
|
|
||||||
(interactive "P")
|
|
||||||
(let* ((entry (devdocs--read-entry "Go to documentation: "
|
|
||||||
(devdocs--relevant-docs ask-docs)
|
|
||||||
initial-input))
|
|
||||||
(buffer (devdocs--render entry))
|
|
||||||
(window (display-buffer buffer)))
|
|
||||||
(when window
|
|
||||||
(with-selected-window window
|
|
||||||
(devdocs-goto-target)
|
|
||||||
(recenter 0))
|
|
||||||
(when devdocs-window-select
|
|
||||||
(select-window window)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-peruse (doc)
|
|
||||||
"Read a document from the first page."
|
|
||||||
(interactive (list (devdocs--read-document "Peruse documentation: ")))
|
|
||||||
(pop-to-buffer (devdocs-goto-page doc 0)))
|
|
||||||
|
|
||||||
;; Don't show devdocs-mode specific commands in M-x
|
|
||||||
(dolist (sym '(devdocs-goto-target devdocs-go-back devdocs-go-forward
|
|
||||||
devdocs-next-entry devdocs-previous-entry devdocs-goto-page
|
|
||||||
devdocs-first-page devdocs-last-page devdocs-next-page
|
|
||||||
devdocs-previous-page devdocs-copy-url))
|
|
||||||
(put sym 'completion-predicate (lambda (_ buffer)
|
|
||||||
(provided-mode-derived-p
|
|
||||||
(buffer-local-value 'major-mode buffer)
|
|
||||||
'devdocs-mode))))
|
|
||||||
|
|
||||||
;;; Compatibility with the old devdocs package
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-search (query)
|
|
||||||
"Search for QUERY in the DevDocs website."
|
|
||||||
(interactive (list (read-from-minibuffer
|
|
||||||
(format "Search %s: " devdocs-site-url)
|
|
||||||
nil nil nil nil (thing-at-point 'symbol))))
|
|
||||||
(browse-url (format "%s/#q=%s" devdocs-site-url (url-hexify-string query))))
|
|
||||||
|
|
||||||
(provide 'devdocs)
|
|
||||||
;;; devdocs.el ends here
|
|
|
@ -1,6 +1,6 @@
|
||||||
(define-package "devdocs-browser" "20240511.306" "Browse devdocs.io documents using EWW"
|
(define-package "devdocs-browser" "20231231.1455" "Browse devdocs.io documents using EWW"
|
||||||
'((emacs "27.1"))
|
'((emacs "27.1"))
|
||||||
:commit "0655b89651458777354a3b89c1d486e0fda1928d" :authors
|
:commit "afc460e687bec4eb947ab85d207778fc3b9b3bbc" :authors
|
||||||
'(("blahgeek" . "i@blahgeek.com"))
|
'(("blahgeek" . "i@blahgeek.com"))
|
||||||
:maintainers
|
:maintainers
|
||||||
'(("blahgeek" . "i@blahgeek.com"))
|
'(("blahgeek" . "i@blahgeek.com"))
|
|
@ -32,7 +32,6 @@
|
||||||
(require 'eww)
|
(require 'eww)
|
||||||
(require 'eldoc)
|
(require 'eldoc)
|
||||||
(require 'imenu)
|
(require 'imenu)
|
||||||
(require 'seq)
|
|
||||||
|
|
||||||
|
|
||||||
(defgroup devdocs-browser nil
|
(defgroup devdocs-browser nil
|
||||||
|
@ -40,40 +39,12 @@
|
||||||
:group 'tools
|
:group 'tools
|
||||||
:group 'web)
|
:group 'web)
|
||||||
|
|
||||||
|
(defcustom devdocs-browser-cache-directory
|
||||||
;; Following are faces for <h1> to <h5> elements.
|
|
||||||
;; We do not reuse `shr-h1' etc. face because:
|
|
||||||
;; - they are only available since emacs 28
|
|
||||||
;; - devdocs documents usually have lower level of headings (e.g. H2 and H3 is more common), so we want different rules as the general version
|
|
||||||
|
|
||||||
(defface devdocs-browser-h1
|
|
||||||
'((t :height 1.3 :weight bold))
|
|
||||||
"Face for <h1> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defface devdocs-browser-h2
|
|
||||||
'((t :height 1.2 :weight bold))
|
|
||||||
"Face for <h2> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defface devdocs-browser-h3
|
|
||||||
'((t :height 1.1 :weight bold))
|
|
||||||
"Face for <h3> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defface devdocs-browser-h4
|
|
||||||
'((t :weight bold))
|
|
||||||
"Face for <h4> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defface devdocs-browser-h5
|
|
||||||
'((t :slant italic))
|
|
||||||
"Face for <h5> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-data-directory
|
|
||||||
(expand-file-name "devdocs-browser" user-emacs-directory)
|
(expand-file-name "devdocs-browser" user-emacs-directory)
|
||||||
"Directory to store devdocs data files."
|
"Directory to store devdocs cache files."
|
||||||
:type 'directory
|
:type 'directory
|
||||||
:group 'devdocs-browser)
|
:group 'devdocs-browser)
|
||||||
|
|
||||||
(defalias 'devdocs-browser-cache-directory 'devdocs-browser-data-directory)
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-base-url "https://devdocs.io/"
|
(defcustom devdocs-browser-base-url "https://devdocs.io/"
|
||||||
"Base URL to fetch json metadata files."
|
"Base URL to fetch json metadata files."
|
||||||
:type 'string)
|
:type 'string)
|
||||||
|
@ -189,20 +160,37 @@ See https://prismjs.com/ for list of language names."
|
||||||
(insert (devdocs-browser--eww-fontify-pre dom))
|
(insert (devdocs-browser--eww-fontify-pre dom))
|
||||||
(shr-ensure-newline)))
|
(shr-ensure-newline)))
|
||||||
|
|
||||||
(defun devdocs-browser--eww-tag-header (level dom)
|
(defun devdocs-browser--eww-tag-maybe-set-title (dom)
|
||||||
"Render function for header DOM with LEVEL (number)."
|
"Maybe set DOM as title if it's not set yet."
|
||||||
;; use h1/h2/h3 as title if not set yet
|
(when (zerop (length (plist-get eww-data :title)))
|
||||||
(when (and (<= level 3)
|
(eww-tag-title dom)))
|
||||||
(zerop (length (plist-get eww-data :title))))
|
|
||||||
(eww-tag-title dom))
|
|
||||||
|
|
||||||
;; similar to shr-heading
|
(defun devdocs-browser--eww-tag-h1 (dom)
|
||||||
(shr-ensure-paragraph)
|
"Rendering function for h1 DOM. Maybe use it as title."
|
||||||
(let ((start (point)))
|
(devdocs-browser--eww-tag-maybe-set-title dom)
|
||||||
(shr-fontize-dom dom (intern (concat "devdocs-browser-h" (number-to-string level))))
|
(shr-tag-h1 dom))
|
||||||
;; this is new since emacs 30, to support outline function
|
|
||||||
(put-text-property start (pos-eol) 'outline-level level))
|
(defun devdocs-browser--eww-tag-h2 (dom)
|
||||||
(shr-ensure-paragraph))
|
"Rendering function for h2 DOM. Maybe use it as title."
|
||||||
|
(devdocs-browser--eww-tag-maybe-set-title dom)
|
||||||
|
(shr-heading dom (if shr-use-fonts
|
||||||
|
'(variable-pitch (:height 1.2 :weight bold))
|
||||||
|
'bold)))
|
||||||
|
|
||||||
|
(defun devdocs-browser--eww-tag-h3 (dom)
|
||||||
|
"Rendering function for h2 DOM. Maybe use it as title."
|
||||||
|
(devdocs-browser--eww-tag-maybe-set-title dom)
|
||||||
|
(shr-heading dom (if shr-use-fonts
|
||||||
|
'(variable-pitch (:height 1.1 :weight bold))
|
||||||
|
'bold)))
|
||||||
|
|
||||||
|
(defun devdocs-browser--eww-tag-h4 (dom)
|
||||||
|
"Rendering function for h4 DOM."
|
||||||
|
(shr-heading dom 'bold))
|
||||||
|
|
||||||
|
(defun devdocs-browser--eww-tag-h5 (dom)
|
||||||
|
"Rendering function for h5 DOM."
|
||||||
|
(shr-heading dom 'italic))
|
||||||
|
|
||||||
(defun devdocs-browser--eww-tag-generic-ensure-paragraph (dom)
|
(defun devdocs-browser--eww-tag-generic-ensure-paragraph (dom)
|
||||||
"Rendering function for generic DOM while ensuring paragraph."
|
"Rendering function for generic DOM while ensuring paragraph."
|
||||||
|
@ -296,7 +284,7 @@ Can be used as `imenu-create-index-function'."
|
||||||
(path (plist-get entry :path))
|
(path (plist-get entry :path))
|
||||||
(url (url-generic-parse-url path))
|
(url (url-generic-parse-url path))
|
||||||
(target (url-target url))
|
(target (url-target url))
|
||||||
((equal (url-filename url) (url-filename page-url))))
|
(_ (equal (url-filename url) (url-filename page-url))))
|
||||||
(cons name (devdocs-browser--position-by-target target))))
|
(cons name (devdocs-browser--position-by-target target))))
|
||||||
entries))))
|
entries))))
|
||||||
|
|
||||||
|
@ -337,12 +325,13 @@ Can be used as `imenu-create-index-function'."
|
||||||
(setq-local shr-external-rendering-functions
|
(setq-local shr-external-rendering-functions
|
||||||
(append shr-external-rendering-functions
|
(append shr-external-rendering-functions
|
||||||
'((pre . devdocs-browser--eww-tag-pre)
|
'((pre . devdocs-browser--eww-tag-pre)
|
||||||
|
(h1 . devdocs-browser--eww-tag-h1)
|
||||||
|
(h2 . devdocs-browser--eww-tag-h2)
|
||||||
|
(h3 . devdocs-browser--eww-tag-h3)
|
||||||
|
(h4 . devdocs-browser--eww-tag-h4)
|
||||||
|
(h5 . devdocs-browser--eww-tag-h5)
|
||||||
(summary . devdocs-browser--eww-tag-generic-ensure-paragraph)
|
(summary . devdocs-browser--eww-tag-generic-ensure-paragraph)
|
||||||
(section . devdocs-browser--eww-tag-generic-ensure-paragraph))
|
(section . devdocs-browser--eww-tag-generic-ensure-paragraph))))
|
||||||
(mapcar (lambda (level)
|
|
||||||
(cons (intern (concat "h" (number-to-string level)))
|
|
||||||
(apply-partially #'devdocs-browser--eww-tag-header level)))
|
|
||||||
(number-sequence 1 5))))
|
|
||||||
(setq-local imenu-create-index-function
|
(setq-local imenu-create-index-function
|
||||||
#'devdocs-browser--imenu-create-index)
|
#'devdocs-browser--imenu-create-index)
|
||||||
(when (boundp 'eww-auto-rename-buffer)
|
(when (boundp 'eww-auto-rename-buffer)
|
||||||
|
@ -362,12 +351,13 @@ Can be used as `imenu-create-index-function'."
|
||||||
(defun devdocs-browser--completing-read (prompt collection &optional def)
|
(defun devdocs-browser--completing-read (prompt collection &optional def)
|
||||||
"Helper function for `completing-read'.
|
"Helper function for `completing-read'.
|
||||||
PROMPT: same meaning, but this function will append ';' at the end;
|
PROMPT: same meaning, but this function will append ';' at the end;
|
||||||
COLLECTION: alist or hashtable of (name . props), where props is a plist with
|
COLLECTION: alist of (name . props), where props is a plist with
|
||||||
possibly the following keys: :value, :annotation, :group;
|
possibly the following keys: :value, :annotation, :group;
|
||||||
if :group is not nil and name starts with '<group>: ', its removed.
|
if :group is not nil and name starts with '<group>: ', its removed.
|
||||||
DEF: same meaning;"
|
DEF: same meaning;"
|
||||||
;; convert collection to hashtables for faster completion. `complete-with-action' also supports that.
|
;; convert collection to hashtables for faster completion. `complete-with-action' also supports that.
|
||||||
(let* (collection-ht
|
(setq collection (delq nil collection))
|
||||||
|
(let* ((collection-ht (make-hash-table :test 'equal :size (length collection)))
|
||||||
(annotation-function
|
(annotation-function
|
||||||
(lambda (s)
|
(lambda (s)
|
||||||
(let ((annotation (plist-get (gethash s collection-ht) :annotation)))
|
(let ((annotation (plist-get (gethash s collection-ht) :annotation)))
|
||||||
|
@ -382,13 +372,8 @@ DEF: same meaning;"
|
||||||
(replace-match "" t t s)
|
(replace-match "" t t s)
|
||||||
s))
|
s))
|
||||||
(t group))))))
|
(t group))))))
|
||||||
(if (hash-table-p collection)
|
(mapc (lambda (elem) (puthash (car elem) (cdr elem) collection-ht))
|
||||||
(setq collection-ht collection)
|
collection)
|
||||||
(setq collection-ht (make-hash-table :test 'equal :size (length collection)))
|
|
||||||
(mapc (lambda (elem)
|
|
||||||
(when elem
|
|
||||||
(puthash (car elem) (cdr elem) collection-ht)))
|
|
||||||
collection))
|
|
||||||
(setq prompt (concat prompt
|
(setq prompt (concat prompt
|
||||||
(when def
|
(when def
|
||||||
(format " (default %s)" (funcall group-function def t)))
|
(format " (default %s)" (funcall group-function def t)))
|
||||||
|
@ -399,7 +384,7 @@ DEF: same meaning;"
|
||||||
(if (eq action 'metadata)
|
(if (eq action 'metadata)
|
||||||
`(metadata . ((annotation-function . ,annotation-function)
|
`(metadata . ((annotation-function . ,annotation-function)
|
||||||
(group-function . ,group-function)))
|
(group-function . ,group-function)))
|
||||||
(complete-with-action action collection-ht str pred)))
|
(complete-with-action action collection str pred)))
|
||||||
nil t ;; require-match
|
nil t ;; require-match
|
||||||
nil nil def)))
|
nil nil def)))
|
||||||
(or (plist-get (gethash res collection-ht) :value)
|
(or (plist-get (gethash res collection-ht) :value)
|
||||||
|
@ -411,7 +396,7 @@ DEF: same meaning;"
|
||||||
|
|
||||||
(defun devdocs-browser--read-json (file-path)
|
(defun devdocs-browser--read-json (file-path)
|
||||||
"Read json file in FILE-PATH, if it's a relative path, find it in cache dir."
|
"Read json file in FILE-PATH, if it's a relative path, find it in cache dir."
|
||||||
(let ((filename (expand-file-name file-path devdocs-browser-data-directory)))
|
(let ((filename (expand-file-name file-path devdocs-browser-cache-directory)))
|
||||||
(when (file-exists-p filename)
|
(when (file-exists-p filename)
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert-file-contents filename)
|
(insert-file-contents filename)
|
||||||
|
@ -420,7 +405,7 @@ DEF: same meaning;"
|
||||||
(defun devdocs-browser--fetch-json (url-path file-path &optional base-url)
|
(defun devdocs-browser--fetch-json (url-path file-path &optional base-url)
|
||||||
"Fetch json from BASE-URL / URL-PATH, also save to FILE-PATH.
|
"Fetch json from BASE-URL / URL-PATH, also save to FILE-PATH.
|
||||||
BASE-URL defaults to `devdocs-browser-base-url'."
|
BASE-URL defaults to `devdocs-browser-base-url'."
|
||||||
(let ((cache-filename (expand-file-name file-path devdocs-browser-data-directory)))
|
(let ((cache-filename (expand-file-name file-path devdocs-browser-cache-directory)))
|
||||||
(unless (file-exists-p (file-name-directory cache-filename))
|
(unless (file-exists-p (file-name-directory cache-filename))
|
||||||
(make-directory (file-name-directory cache-filename) t))
|
(make-directory (file-name-directory cache-filename) t))
|
||||||
(with-temp-file cache-filename
|
(with-temp-file cache-filename
|
||||||
|
@ -462,18 +447,13 @@ To upgrade docs content, see `devdocs-browser-upgrade-doc'."
|
||||||
(equal (plist-get doc :name) slug-or-name)))
|
(equal (plist-get doc :name) slug-or-name)))
|
||||||
docs-list)))
|
docs-list)))
|
||||||
|
|
||||||
(defcustom devdocs-browser-enable-cache t
|
(defvar devdocs-browser--docs-cache '() "Cached doc indexes plist.")
|
||||||
"Whether cache doc indices in memory."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'devdocs-browser)
|
|
||||||
|
|
||||||
(defvar devdocs-browser--docs-cache '() "Cached doc indices plist.")
|
|
||||||
|
|
||||||
(defun devdocs-browser--install-doc-internal (doc)
|
(defun devdocs-browser--install-doc-internal (doc)
|
||||||
"(Re-)install doc identified by plist DOC. Return t if success."
|
"(Re-)install doc identified by plist DOC. Return t if success."
|
||||||
(let* ((slug (plist-get doc :slug))
|
(let* ((slug (plist-get doc :slug))
|
||||||
(mtime (plist-get doc :mtime))
|
(mtime (plist-get doc :mtime))
|
||||||
(docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory))
|
(docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory))
|
||||||
(doc-dir (expand-file-name slug docs-dir))
|
(doc-dir (expand-file-name slug docs-dir))
|
||||||
success)
|
success)
|
||||||
(unless (file-exists-p docs-dir)
|
(unless (file-exists-p docs-dir)
|
||||||
|
@ -498,7 +478,7 @@ To upgrade docs content, see `devdocs-browser-upgrade-doc'."
|
||||||
(message "Failed to install devdocs doc %s" slug))
|
(message "Failed to install devdocs doc %s" slug))
|
||||||
;; remove cache
|
;; remove cache
|
||||||
(setq devdocs-browser--docs-cache
|
(setq devdocs-browser--docs-cache
|
||||||
(plist-put devdocs-browser--docs-cache slug nil #'equal))
|
(lax-plist-put devdocs-browser--docs-cache slug nil))
|
||||||
success))
|
success))
|
||||||
|
|
||||||
(defun devdocs-browser--doc-readable-name (doc)
|
(defun devdocs-browser--doc-readable-name (doc)
|
||||||
|
@ -548,12 +528,12 @@ When called interactively, user can choose from the list."
|
||||||
(interactive (list (completing-read "Uninstall doc: "
|
(interactive (list (completing-read "Uninstall doc: "
|
||||||
(devdocs-browser-list-installed-slugs)
|
(devdocs-browser-list-installed-slugs)
|
||||||
nil t)))
|
nil t)))
|
||||||
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory))
|
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory))
|
||||||
(doc-dir (expand-file-name slug docs-dir)))
|
(doc-dir (expand-file-name slug docs-dir)))
|
||||||
(when (file-exists-p doc-dir)
|
(when (file-exists-p doc-dir)
|
||||||
(delete-directory doc-dir t)))
|
(delete-directory doc-dir t)))
|
||||||
(setq devdocs-browser--docs-cache
|
(setq devdocs-browser--docs-cache
|
||||||
(plist-put devdocs-browser--docs-cache slug nil #'equal)))
|
(lax-plist-put devdocs-browser--docs-cache slug nil)))
|
||||||
|
|
||||||
(defun devdocs-browser--upgrade-readable-name (old-doc new-doc)
|
(defun devdocs-browser--upgrade-readable-name (old-doc new-doc)
|
||||||
"Get human readable name for upgrade from OLD-DOC to NEW-DOC."
|
"Get human readable name for upgrade from OLD-DOC to NEW-DOC."
|
||||||
|
@ -622,7 +602,7 @@ You may need to call `devdocs-browser-update-docs' first."
|
||||||
|
|
||||||
(defun devdocs-browser-list-installed-slugs ()
|
(defun devdocs-browser-list-installed-slugs ()
|
||||||
"Get a list of installed docs' slug name."
|
"Get a list of installed docs' slug name."
|
||||||
(let ((dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory)))
|
(let ((dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory)))
|
||||||
(when (file-exists-p dir)
|
(when (file-exists-p dir)
|
||||||
(directory-files dir nil
|
(directory-files dir nil
|
||||||
;; ignore ".", ".." and hidden files
|
;; ignore ".", ".." and hidden files
|
||||||
|
@ -644,9 +624,9 @@ You may need to call `devdocs-browser-update-docs' first."
|
||||||
(defun devdocs-browser--load-doc (slug &optional refresh-cache)
|
(defun devdocs-browser--load-doc (slug &optional refresh-cache)
|
||||||
"Load doc identified by SLUG, reload cache if REFRESH-CACHE is not nil.
|
"Load doc identified by SLUG, reload cache if REFRESH-CACHE is not nil.
|
||||||
Result is a plist metadata, with an extra :index field at the beginning."
|
Result is a plist metadata, with an extra :index field at the beginning."
|
||||||
(or (and (not refresh-cache) (plist-get devdocs-browser--docs-cache slug #'equal))
|
(or (and (not refresh-cache) (lax-plist-get devdocs-browser--docs-cache slug))
|
||||||
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir
|
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir
|
||||||
devdocs-browser-data-directory))
|
devdocs-browser-cache-directory))
|
||||||
(doc-dir (expand-file-name slug docs-dir))
|
(doc-dir (expand-file-name slug docs-dir))
|
||||||
(metadata-filename (expand-file-name devdocs-browser--metadata-filename doc-dir))
|
(metadata-filename (expand-file-name devdocs-browser--metadata-filename doc-dir))
|
||||||
(metadata nil)
|
(metadata nil)
|
||||||
|
@ -658,16 +638,15 @@ Result is a plist metadata, with an extra :index field at the beginning."
|
||||||
(insert-file-contents metadata-filename)
|
(insert-file-contents metadata-filename)
|
||||||
(setq metadata (read (current-buffer))))
|
(setq metadata (read (current-buffer))))
|
||||||
(setq res (append `(:index ,index) metadata))
|
(setq res (append `(:index ,index) metadata))
|
||||||
(when devdocs-browser-enable-cache
|
(setq devdocs-browser--docs-cache
|
||||||
(setq devdocs-browser--docs-cache
|
(lax-plist-put devdocs-browser--docs-cache slug res)))
|
||||||
(plist-put devdocs-browser--docs-cache slug res #'equal))))
|
|
||||||
res)))
|
res)))
|
||||||
|
|
||||||
(defun devdocs-browser--download-offline-data-internal (doc)
|
(defun devdocs-browser--download-offline-data-internal (doc)
|
||||||
"(re-)Download and extract offline data for DOC."
|
"(re-)Download and extract offline data for DOC."
|
||||||
(let* ((slug (plist-get doc :slug))
|
(let* ((slug (plist-get doc :slug))
|
||||||
(mtime (plist-get doc :mtime))
|
(mtime (plist-get doc :mtime))
|
||||||
(docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory))
|
(docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory))
|
||||||
(doc-dir (expand-file-name slug docs-dir))
|
(doc-dir (expand-file-name slug docs-dir))
|
||||||
(data-dir (expand-file-name devdocs-browser--offline-data-dir-name doc-dir))
|
(data-dir (expand-file-name devdocs-browser--offline-data-dir-name doc-dir))
|
||||||
success)
|
success)
|
||||||
|
@ -703,7 +682,7 @@ Result is a plist metadata, with an extra :index field at the beginning."
|
||||||
|
|
||||||
(defun devdocs-browser-offline-data-dir (slug)
|
(defun devdocs-browser-offline-data-dir (slug)
|
||||||
"Return doc SLUG's offline data dir if present, return nil otherwise."
|
"Return doc SLUG's offline data dir if present, return nil otherwise."
|
||||||
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory))
|
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory))
|
||||||
(doc-dir (expand-file-name slug docs-dir))
|
(doc-dir (expand-file-name slug docs-dir))
|
||||||
(data-dir (expand-file-name devdocs-browser--offline-data-dir-name doc-dir)))
|
(data-dir (expand-file-name devdocs-browser--offline-data-dir-name doc-dir)))
|
||||||
(when (file-exists-p data-dir)
|
(when (file-exists-p data-dir)
|
||||||
|
@ -799,8 +778,7 @@ When called interactively, user can choose from the list."
|
||||||
(let ((current-word-regex
|
(let ((current-word-regex
|
||||||
(when-let ((word (thing-at-point 'word t)))
|
(when-let ((word (thing-at-point 'word t)))
|
||||||
(concat "\\<" (regexp-quote word) "\\>")))
|
(concat "\\<" (regexp-quote word) "\\>")))
|
||||||
(rows (make-hash-table :test 'equal))
|
slugs rows def)
|
||||||
slugs def)
|
|
||||||
(dolist (slug-or-name slug-or-name-list)
|
(dolist (slug-or-name slug-or-name-list)
|
||||||
(when-let* ((doc-simple (devdocs-browser-find-installed-doc slug-or-name))
|
(when-let* ((doc-simple (devdocs-browser-find-installed-doc slug-or-name))
|
||||||
(slug (plist-get doc-simple :slug))
|
(slug (plist-get doc-simple :slug))
|
||||||
|
@ -808,22 +786,25 @@ When called interactively, user can choose from the list."
|
||||||
(index (plist-get doc :index))
|
(index (plist-get doc :index))
|
||||||
(entries (plist-get index :entries)))
|
(entries (plist-get index :entries)))
|
||||||
(setq slugs (push slug slugs))
|
(setq slugs (push slug slugs))
|
||||||
(puthash (format "%s: INDEX PAGE" slug)
|
(let ((new-rows
|
||||||
`(:value (,doc "index")
|
(mapcar
|
||||||
:group ,slug)
|
(lambda (entry)
|
||||||
rows)
|
(let* ((name (plist-get entry :name))
|
||||||
(seq-doseq (entry entries)
|
(path (plist-get entry :path))
|
||||||
(let* ((name (plist-get entry :name))
|
(type (plist-get entry :type))
|
||||||
(path (plist-get entry :path))
|
(title (concat slug ": " name)))
|
||||||
(type (plist-get entry :type))
|
(when (and (null def) current-word-regex)
|
||||||
(title (concat slug ": " name)))
|
(when (string-match-p current-word-regex name)
|
||||||
(when (and (null def) current-word-regex)
|
(setq def title)))
|
||||||
(when (string-match-p current-word-regex name)
|
(cons title `(:value (,doc ,path)
|
||||||
(setq def title)))
|
:group ,slug
|
||||||
(puthash title `(:value (,doc ,path)
|
:annotation ,type))))
|
||||||
:group ,slug
|
entries)))
|
||||||
:annotation ,type)
|
(setq rows (append new-rows rows))
|
||||||
rows)))))
|
(push (cons (format "%s: INDEX PAGE" slug)
|
||||||
|
`(:value (,doc "index")
|
||||||
|
:group ,slug))
|
||||||
|
rows))))
|
||||||
(let* ((selected-value
|
(let* ((selected-value
|
||||||
(devdocs-browser--completing-read
|
(devdocs-browser--completing-read
|
||||||
(format "Devdocs browser [%s]" (mapconcat #'identity slugs ","))
|
(format "Devdocs browser [%s]" (mapconcat #'identity slugs ","))
|
||||||
|
@ -831,12 +812,6 @@ When called interactively, user can choose from the list."
|
||||||
(when selected-value
|
(when selected-value
|
||||||
(apply #'devdocs-browser--eww-open selected-value)))))
|
(apply #'devdocs-browser--eww-open selected-value)))))
|
||||||
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-open-fallback-to-all-docs t
|
|
||||||
"When not sure which docs to use, whether `devdocs-browser-open' should use all installed docs, or just ask the user to pick one (like `devdocs-browser-open-in')."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'devdocs-browser)
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun devdocs-browser-open ()
|
(defun devdocs-browser-open ()
|
||||||
"Open entry in active docs.
|
"Open entry in active docs.
|
||||||
|
@ -845,12 +820,7 @@ or `devdocs-browser-major-mode-docs-alist',
|
||||||
or the current doc type if called in a devdocs eww buffer.
|
or the current doc type if called in a devdocs eww buffer.
|
||||||
When all of them are nil, all installed docs are used."
|
When all of them are nil, all installed docs are used."
|
||||||
(interactive)
|
(interactive)
|
||||||
(if devdocs-browser-open-fallback-to-all-docs
|
(devdocs-browser-open-in (devdocs-browser--default-active-slugs)))
|
||||||
(devdocs-browser-open-in (devdocs-browser--default-active-slugs))
|
|
||||||
(let ((slugs (devdocs-browser--default-active-slugs 'no-fallback-all)))
|
|
||||||
(if slugs
|
|
||||||
(devdocs-browser-open-in slugs)
|
|
||||||
(call-interactively 'devdocs-browser-open-in)))))
|
|
||||||
|
|
||||||
|
|
||||||
(provide 'devdocs-browser)
|
(provide 'devdocs-browser)
|
|
@ -1,857 +0,0 @@
|
||||||
;;; devdocs-browser.el --- Browse devdocs.io documents using EWW -*- lexical-binding: t; -*-
|
|
||||||
|
|
||||||
;; Copyright (C) 2021
|
|
||||||
|
|
||||||
;; Author: blahgeek <i@blahgeek.com>
|
|
||||||
;; URL: https://github.com/blahgeek/emacs-devdocs-browser
|
|
||||||
;; Version: 20210525
|
|
||||||
;; Keywords: docs, help, tools
|
|
||||||
;; Package-Requires: ((emacs "27.1"))
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
|
||||||
;; it under the terms of the GNU General Public License as published by
|
|
||||||
;; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
|
|
||||||
;; This program is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
;; GNU General Public License for more details.
|
|
||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Browse devdocs.io documents inside Emacs using EWW.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'files)
|
|
||||||
(require 'shr)
|
|
||||||
(require 'eww)
|
|
||||||
(require 'eldoc)
|
|
||||||
(require 'imenu)
|
|
||||||
(require 'seq)
|
|
||||||
|
|
||||||
|
|
||||||
(defgroup devdocs-browser nil
|
|
||||||
"Browse devdocs.io."
|
|
||||||
:group 'tools
|
|
||||||
:group 'web)
|
|
||||||
|
|
||||||
|
|
||||||
;; Following are faces for <h1> to <h5> elements.
|
|
||||||
;; We do not reuse `shr-h1' etc. face because:
|
|
||||||
;; - they are only available since emacs 28
|
|
||||||
;; - devdocs documents usually have lower level of headings (e.g. H2 and H3 is more common), so we want different rules as the general version
|
|
||||||
|
|
||||||
(defface devdocs-browser-h1
|
|
||||||
'((t :height 1.3 :weight bold))
|
|
||||||
"Face for <h1> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defface devdocs-browser-h2
|
|
||||||
'((t :height 1.2 :weight bold))
|
|
||||||
"Face for <h2> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defface devdocs-browser-h3
|
|
||||||
'((t :height 1.1 :weight bold))
|
|
||||||
"Face for <h3> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defface devdocs-browser-h4
|
|
||||||
'((t :weight bold))
|
|
||||||
"Face for <h4> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defface devdocs-browser-h5
|
|
||||||
'((t :slant italic))
|
|
||||||
"Face for <h5> elements for devdocs-browser.")
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-data-directory
|
|
||||||
(expand-file-name "devdocs-browser" user-emacs-directory)
|
|
||||||
"Directory to store devdocs data files."
|
|
||||||
:type 'directory
|
|
||||||
:group 'devdocs-browser)
|
|
||||||
|
|
||||||
(defalias 'devdocs-browser-cache-directory 'devdocs-browser-data-directory)
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-base-url "https://devdocs.io/"
|
|
||||||
"Base URL to fetch json metadata files."
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-doc-base-url "https://documents.devdocs.io/"
|
|
||||||
"Base URL for doc contents."
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-major-mode-docs-alist
|
|
||||||
'((c++-mode . ("cpp"))
|
|
||||||
(c-mode . ("c"))
|
|
||||||
(go-mode . ("go"))
|
|
||||||
(python-mode . ("Python"))
|
|
||||||
(emacs-lisp-mode . ("elisp"))
|
|
||||||
(rust-mode . ("rust"))
|
|
||||||
(cmake-mode . ("CMake")))
|
|
||||||
"Alist of MAJOR-MODE and list of docset names.
|
|
||||||
When calling `devdocs-browser-open', this variable will be used
|
|
||||||
to pick a list of docsets based on the current MAJOR-MODE.
|
|
||||||
Docset name may be SLUG (e.g. 'python~3.8') or NAME (e.g. 'Python'),
|
|
||||||
if it's a NAME and multiple choices are possible,
|
|
||||||
one of the installed docs with the NAME will be used.
|
|
||||||
Also see `devdocs-browser-active-docs'."
|
|
||||||
:type '(alist :key-type function
|
|
||||||
:value-type (list string)))
|
|
||||||
|
|
||||||
(defvar-local devdocs-browser-active-docs
|
|
||||||
nil
|
|
||||||
"List of docset names used by `devdocs-browser-open' to pick docsets.
|
|
||||||
If this var is set to non-nil,
|
|
||||||
it have higher priority than `devdocs-browser-major-mode-docs-alist'.
|
|
||||||
See `devdocs-browser-major-mode-docs-alist' for the meaning of NAME.")
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-highlight-lang-mode-alist '()
|
|
||||||
"Alist of language name and MAJOR-MODE, to highlight HTML pre blocks.
|
|
||||||
If language is not found in this alist,
|
|
||||||
`devdocs-browser-highlight-lang-mode-alist-default' will be used.
|
|
||||||
See https://prismjs.com/ for list of language names."
|
|
||||||
:type '(alist :key-type string
|
|
||||||
:value-type function))
|
|
||||||
|
|
||||||
(defvar devdocs-browser-highlight-lang-mode-alist-default
|
|
||||||
'(("html" . html-mode)
|
|
||||||
("xml" . xml-mode)
|
|
||||||
("css" . css-mode)
|
|
||||||
("clike" . c-mode)
|
|
||||||
("javascript" . js-mode)
|
|
||||||
("js" . js-mode)
|
|
||||||
("jsx" . js-mode)
|
|
||||||
("bash" . sh-mode)
|
|
||||||
("shell" . sh-mode)
|
|
||||||
("c" . c-mode)
|
|
||||||
("cpp" . c++-mode)
|
|
||||||
("cmake" . cmake-mode)
|
|
||||||
("go" . go-mode)
|
|
||||||
("haskell" . haskell-mode)
|
|
||||||
("hs" . haskell-mode)
|
|
||||||
("java" . java-mode)
|
|
||||||
("json" . js-mode)
|
|
||||||
("elisp" . elisp-mode)
|
|
||||||
("emacs" . elisp-mode)
|
|
||||||
("lua" . lua-mode)
|
|
||||||
("makefile" . makefile-mode)
|
|
||||||
("markdown" . markdown-mode)
|
|
||||||
("md" . markdown-mode)
|
|
||||||
("nginx" . conf-mode)
|
|
||||||
("objectivec" . objc-mode)
|
|
||||||
("objc" . objc-mode)
|
|
||||||
("perl" . perl-mode)
|
|
||||||
("protobuf" . protobuf-mode)
|
|
||||||
("python" . python-mode)
|
|
||||||
("py" . python-mode)
|
|
||||||
("ruby" . ruby-mode)
|
|
||||||
("rust" . rust-mode)
|
|
||||||
("rb" . ruby-mode)
|
|
||||||
("sql" . sql-mode)
|
|
||||||
("typescript" . typescript-mode))
|
|
||||||
"Default value for `devdocs-browser-highlight-lang-mode-alist'.")
|
|
||||||
|
|
||||||
|
|
||||||
(defun devdocs-browser--clear-dom-id-attr (dom)
|
|
||||||
"Clear id attribute for DOM and its children."
|
|
||||||
(dom-remove-attribute dom 'id)
|
|
||||||
(mapc #'devdocs-browser--clear-dom-id-attr (dom-non-text-children dom)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-fontify-pre (dom)
|
|
||||||
"Return fontified string for pre DOM."
|
|
||||||
(with-temp-buffer
|
|
||||||
(shr-generic dom)
|
|
||||||
(when (> shr-indentation 0)
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (not (eobp))
|
|
||||||
(shr-indent)
|
|
||||||
(forward-line 1))))
|
|
||||||
(let* ((language (dom-attr dom 'data-language))
|
|
||||||
(mode (cdr (or (assoc language devdocs-browser-highlight-lang-mode-alist)
|
|
||||||
(assoc language devdocs-browser-highlight-lang-mode-alist-default)))))
|
|
||||||
(when (fboundp mode)
|
|
||||||
(delay-mode-hooks (funcall mode))
|
|
||||||
(font-lock-default-function mode)
|
|
||||||
(font-lock-default-fontify-region (point-min) (point-max) nil)))
|
|
||||||
(buffer-string)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-tag-pre (dom)
|
|
||||||
"Rendering function for pre DOM."
|
|
||||||
;; must clear all 'id' attributes in dom.
|
|
||||||
;; otherwise, shr would try to add text properties based on it, but since they are rendered in temp-buffer, the marker would be invalid
|
|
||||||
(devdocs-browser--clear-dom-id-attr dom)
|
|
||||||
(let ((shr-folding-mode 'none)
|
|
||||||
(shr-current-font 'default))
|
|
||||||
(shr-ensure-newline)
|
|
||||||
(insert (devdocs-browser--eww-fontify-pre dom))
|
|
||||||
(shr-ensure-newline)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-tag-header (level dom)
|
|
||||||
"Render function for header DOM with LEVEL (number)."
|
|
||||||
;; use h1/h2/h3 as title if not set yet
|
|
||||||
(when (and (<= level 3)
|
|
||||||
(zerop (length (plist-get eww-data :title))))
|
|
||||||
(eww-tag-title dom))
|
|
||||||
|
|
||||||
;; similar to shr-heading
|
|
||||||
(shr-ensure-paragraph)
|
|
||||||
(let ((start (point)))
|
|
||||||
(shr-fontize-dom dom (intern (concat "devdocs-browser-h" (number-to-string level))))
|
|
||||||
;; this is new since emacs 30, to support outline function
|
|
||||||
(put-text-property start (pos-eol) 'outline-level level))
|
|
||||||
(shr-ensure-paragraph))
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-tag-generic-ensure-paragraph (dom)
|
|
||||||
"Rendering function for generic DOM while ensuring paragraph."
|
|
||||||
(shr-ensure-paragraph)
|
|
||||||
(shr-generic dom))
|
|
||||||
|
|
||||||
(defvar-local devdocs-browser--eww-data '()
|
|
||||||
"Plist data for current eww page, contain :doc and :path.")
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-fix-url (url)
|
|
||||||
"Fix links' URL in docs by appending suffix and mtime."
|
|
||||||
;; shr-expand-url may be call in a temp buffer
|
|
||||||
;; we need to temporary bind this buffer to access the buffer-local variable.
|
|
||||||
(with-current-buffer (window-buffer)
|
|
||||||
(let ((url-parsed (url-generic-parse-url url))
|
|
||||||
(root-url-parsed (url-generic-parse-url (plist-get eww-data :url)))
|
|
||||||
(mtime (plist-get (plist-get devdocs-browser--eww-data :doc) :mtime)))
|
|
||||||
(when (and mtime
|
|
||||||
(equal (url-type url-parsed) (url-type root-url-parsed))
|
|
||||||
(equal (url-host url-parsed) (url-host root-url-parsed))
|
|
||||||
(not (string-match-p "\\.html" url)))
|
|
||||||
(setf (url-filename url-parsed)
|
|
||||||
(if (equal (url-type url-parsed) "file")
|
|
||||||
(concat (url-filename url-parsed) ".html")
|
|
||||||
(format "%s.html?%s" (url-filename url-parsed) mtime)))
|
|
||||||
(setq url (url-recreate-url url-parsed)))))
|
|
||||||
url)
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-parse-url-path (url)
|
|
||||||
"Return URL's doc :path ('hello/world#target')."
|
|
||||||
;; see devdocs-browser--eww-open for url pattern
|
|
||||||
(when-let* ((url-parsed (url-generic-parse-url url))
|
|
||||||
(doc (plist-get devdocs-browser--eww-data :doc))
|
|
||||||
(slug (plist-get doc :slug))
|
|
||||||
(filename-suffix (if (equal (url-type url-parsed) "file")
|
|
||||||
".html"
|
|
||||||
(format ".html?%s" (plist-get doc :mtime))))
|
|
||||||
(filename-prefix (if (equal (url-type url-parsed) "file")
|
|
||||||
(devdocs-browser-offline-data-dir slug)
|
|
||||||
(concat "/" slug "/")))
|
|
||||||
(path (url-filename url-parsed)))
|
|
||||||
(when (and (string-prefix-p filename-prefix path)
|
|
||||||
(string-suffix-p filename-suffix path))
|
|
||||||
(setq path (string-remove-prefix filename-prefix path))
|
|
||||||
(setq path (string-remove-suffix filename-suffix path))
|
|
||||||
(when (url-target url-parsed)
|
|
||||||
(setq path (concat path "#" (url-target url-parsed))))
|
|
||||||
path)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-page-path ()
|
|
||||||
"Return current page's :path ('hello/world#target')."
|
|
||||||
(devdocs-browser--eww-parse-url-path (plist-get eww-data :url)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-link-eldoc (&optional _)
|
|
||||||
"Show URL link or description at current point."
|
|
||||||
(when-let ((url (get-text-property (point) 'shr-url)))
|
|
||||||
(if-let ((path (devdocs-browser--eww-parse-url-path url)))
|
|
||||||
(let* ((doc (plist-get devdocs-browser--eww-data :doc))
|
|
||||||
(index (plist-get doc :index))
|
|
||||||
(entries (plist-get index :entries))
|
|
||||||
(entry (seq-find
|
|
||||||
(lambda (x) (equal (plist-get x :path) path))
|
|
||||||
entries)))
|
|
||||||
(concat
|
|
||||||
(when entry
|
|
||||||
(propertize (plist-get entry :name) 'face 'font-lock-keyword-face))
|
|
||||||
(when entry
|
|
||||||
(format " (%s): " (plist-get entry :type)))
|
|
||||||
(propertize path 'face 'italic)))
|
|
||||||
(format "External link: %s" (propertize url 'face 'italic)))))
|
|
||||||
|
|
||||||
(defun devdocs-browser--position-by-target (target)
|
|
||||||
"Find buffer position for TARGET (url hash)."
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(when-let ((match (text-property-search-forward 'shr-target-id target #'member)))
|
|
||||||
(prop-match-beginning match))))
|
|
||||||
|
|
||||||
(defun devdocs-browser--imenu-create-index ()
|
|
||||||
"Create index alist for current buffer for imenu.
|
|
||||||
Can be used as `imenu-create-index-function'."
|
|
||||||
(when-let* ((doc (plist-get devdocs-browser--eww-data :doc))
|
|
||||||
(entries (plist-get (plist-get doc :index) :entries))
|
|
||||||
(page-path (devdocs-browser--eww-page-path))
|
|
||||||
(page-url (url-generic-parse-url page-path)))
|
|
||||||
(seq-filter
|
|
||||||
#'identity
|
|
||||||
(mapcar
|
|
||||||
(lambda (entry)
|
|
||||||
(when-let* ((name (plist-get entry :name))
|
|
||||||
(path (plist-get entry :path))
|
|
||||||
(url (url-generic-parse-url path))
|
|
||||||
(target (url-target url))
|
|
||||||
((equal (url-filename url) (url-filename page-url))))
|
|
||||||
(cons name (devdocs-browser--position-by-target target))))
|
|
||||||
entries))))
|
|
||||||
|
|
||||||
(define-obsolete-function-alias 'devdocs-browser-eww-goto-target 'imenu "20220917")
|
|
||||||
|
|
||||||
(defun devdocs-browser-eww-open-in-default-browser ()
|
|
||||||
"Open current page in devdocs.io in browser."
|
|
||||||
(interactive)
|
|
||||||
(when-let* ((doc (plist-get devdocs-browser--eww-data :doc))
|
|
||||||
(slug (plist-get doc :slug))
|
|
||||||
(path (devdocs-browser--eww-page-path))
|
|
||||||
(url (concat devdocs-browser-base-url slug "/" path)))
|
|
||||||
(browse-url-default-browser url)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-recenter-advice (res)
|
|
||||||
"Recenter current cursor for devdocs buffer, used for advice :filter-return (return `RES')."
|
|
||||||
(when devdocs-browser--eww-data
|
|
||||||
(recenter))
|
|
||||||
res)
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-browse-url-new-window-advice (args)
|
|
||||||
"Advice around `eww-browse-url' with ARGS, set NEW-WINDOW if URL is external."
|
|
||||||
(let ((url (car args))
|
|
||||||
(new-window (cadr args)))
|
|
||||||
(when (and devdocs-browser--eww-data
|
|
||||||
(not (devdocs-browser--eww-parse-url-path url)))
|
|
||||||
(setq new-window t))
|
|
||||||
(list url new-window)))
|
|
||||||
|
|
||||||
(define-minor-mode devdocs-browser-eww-mode
|
|
||||||
"Minor mode for browsing devdocs pages with eww."
|
|
||||||
:lighter " Devdocs"
|
|
||||||
:interactive nil
|
|
||||||
:group 'devdocs-browser
|
|
||||||
:keymap (let ((map (make-sparse-keymap)))
|
|
||||||
(define-key map (kbd "C-c C-o") #'devdocs-browser-eww-open-in-default-browser)
|
|
||||||
map)
|
|
||||||
(setq-local shr-external-rendering-functions
|
|
||||||
(append shr-external-rendering-functions
|
|
||||||
'((pre . devdocs-browser--eww-tag-pre)
|
|
||||||
(summary . devdocs-browser--eww-tag-generic-ensure-paragraph)
|
|
||||||
(section . devdocs-browser--eww-tag-generic-ensure-paragraph))
|
|
||||||
(mapcar (lambda (level)
|
|
||||||
(cons (intern (concat "h" (number-to-string level)))
|
|
||||||
(apply-partially #'devdocs-browser--eww-tag-header level)))
|
|
||||||
(number-sequence 1 5))))
|
|
||||||
(setq-local imenu-create-index-function
|
|
||||||
#'devdocs-browser--imenu-create-index)
|
|
||||||
(when (boundp 'eww-auto-rename-buffer)
|
|
||||||
(setq-local eww-auto-rename-buffer nil))
|
|
||||||
(advice-add 'shr-expand-url :filter-return #'devdocs-browser--eww-fix-url)
|
|
||||||
(advice-add 'eww-display-html :filter-return #'devdocs-browser--eww-recenter-advice)
|
|
||||||
(advice-add 'eww-browse-url :filter-args #'devdocs-browser--eww-browse-url-new-window-advice)
|
|
||||||
(add-hook 'eldoc-documentation-functions #'devdocs-browser--eww-link-eldoc nil t)
|
|
||||||
(eldoc-mode))
|
|
||||||
|
|
||||||
(defvar devdocs-browser--docs-dir "docs")
|
|
||||||
(defvar devdocs-browser--index-json-filename "index.json")
|
|
||||||
(defvar devdocs-browser--metadata-filename "metadata.el")
|
|
||||||
(defvar devdocs-browser--offline-data-json-filename "content.json")
|
|
||||||
(defvar devdocs-browser--offline-data-dir-name "content")
|
|
||||||
|
|
||||||
(defun devdocs-browser--completing-read (prompt collection &optional def)
|
|
||||||
"Helper function for `completing-read'.
|
|
||||||
PROMPT: same meaning, but this function will append ';' at the end;
|
|
||||||
COLLECTION: alist or hashtable of (name . props), where props is a plist with
|
|
||||||
possibly the following keys: :value, :annotation, :group;
|
|
||||||
if :group is not nil and name starts with '<group>: ', its removed.
|
|
||||||
DEF: same meaning;"
|
|
||||||
;; convert collection to hashtables for faster completion. `complete-with-action' also supports that.
|
|
||||||
(let* (collection-ht
|
|
||||||
(annotation-function
|
|
||||||
(lambda (s)
|
|
||||||
(let ((annotation (plist-get (gethash s collection-ht) :annotation)))
|
|
||||||
(if annotation
|
|
||||||
(concat " " annotation)
|
|
||||||
nil))))
|
|
||||||
(group-function
|
|
||||||
(lambda (s transform)
|
|
||||||
(let ((group (plist-get (gethash s collection-ht) :group)))
|
|
||||||
(cond
|
|
||||||
(transform (if (and group (string-match (rx bos (literal group) ": ") s))
|
|
||||||
(replace-match "" t t s)
|
|
||||||
s))
|
|
||||||
(t group))))))
|
|
||||||
(if (hash-table-p collection)
|
|
||||||
(setq collection-ht collection)
|
|
||||||
(setq collection-ht (make-hash-table :test 'equal :size (length collection)))
|
|
||||||
(mapc (lambda (elem)
|
|
||||||
(when elem
|
|
||||||
(puthash (car elem) (cdr elem) collection-ht)))
|
|
||||||
collection))
|
|
||||||
(setq prompt (concat prompt
|
|
||||||
(when def
|
|
||||||
(format " (default %s)" (funcall group-function def t)))
|
|
||||||
": "))
|
|
||||||
(let ((res (completing-read
|
|
||||||
prompt
|
|
||||||
(lambda (str pred action)
|
|
||||||
(if (eq action 'metadata)
|
|
||||||
`(metadata . ((annotation-function . ,annotation-function)
|
|
||||||
(group-function . ,group-function)))
|
|
||||||
(complete-with-action action collection-ht str pred)))
|
|
||||||
nil t ;; require-match
|
|
||||||
nil nil def)))
|
|
||||||
(or (plist-get (gethash res collection-ht) :value)
|
|
||||||
res))))
|
|
||||||
|
|
||||||
(defun devdocs-browser--json-parse-buffer ()
|
|
||||||
"Same as `json-parse-buffer', with custom settings."
|
|
||||||
(json-parse-buffer :object-type 'plist :array-type 'array))
|
|
||||||
|
|
||||||
(defun devdocs-browser--read-json (file-path)
|
|
||||||
"Read json file in FILE-PATH, if it's a relative path, find it in cache dir."
|
|
||||||
(let ((filename (expand-file-name file-path devdocs-browser-data-directory)))
|
|
||||||
(when (file-exists-p filename)
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents filename)
|
|
||||||
(devdocs-browser--json-parse-buffer)))))
|
|
||||||
|
|
||||||
(defun devdocs-browser--fetch-json (url-path file-path &optional base-url)
|
|
||||||
"Fetch json from BASE-URL / URL-PATH, also save to FILE-PATH.
|
|
||||||
BASE-URL defaults to `devdocs-browser-base-url'."
|
|
||||||
(let ((cache-filename (expand-file-name file-path devdocs-browser-data-directory)))
|
|
||||||
(unless (file-exists-p (file-name-directory cache-filename))
|
|
||||||
(make-directory (file-name-directory cache-filename) t))
|
|
||||||
(with-temp-file cache-filename
|
|
||||||
(erase-buffer)
|
|
||||||
(url-insert-file-contents (concat (or base-url devdocs-browser-base-url) url-path))
|
|
||||||
(devdocs-browser--json-parse-buffer))))
|
|
||||||
|
|
||||||
|
|
||||||
(defvar devdocs-browser--docs-list-cache nil "Cached docs list.")
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-browser-list-docs (&optional refresh-cache)
|
|
||||||
"Get doc metadata lists, reload cache if REFRESH-CACHE."
|
|
||||||
(setq devdocs-browser--docs-list-cache
|
|
||||||
(or (and (not refresh-cache) devdocs-browser--docs-list-cache)
|
|
||||||
(and (not refresh-cache) (devdocs-browser--read-json "docs.json"))
|
|
||||||
(devdocs-browser--fetch-json "docs.json" "docs.json"))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-browser-update-metadata ()
|
|
||||||
"Update doc metadata list.
|
|
||||||
To upgrade docs content, see `devdocs-browser-upgrade-doc'."
|
|
||||||
(interactive)
|
|
||||||
(let ((count (length (devdocs-browser-list-docs t))))
|
|
||||||
(message (concat "Doc metadata updated, found total %s docs. "
|
|
||||||
"You may want to run `devdocs-browser-install-doc' "
|
|
||||||
"or `devdocs-browser-upgrade-doc'.")
|
|
||||||
count)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defalias 'devdocs-browser-update-docs 'devdocs-browser-update-metadata)
|
|
||||||
(make-obsolete 'devdocs-browser-update-docs 'devdocs-browser-update-metadata "20231231")
|
|
||||||
|
|
||||||
(defun devdocs-browser-find-doc (slug-or-name)
|
|
||||||
"Find doc from docs list by SLUG-OR-NAME."
|
|
||||||
(let ((docs-list (devdocs-browser-list-docs)))
|
|
||||||
(seq-find (lambda (doc)
|
|
||||||
(or (equal (plist-get doc :slug) slug-or-name)
|
|
||||||
(equal (plist-get doc :name) slug-or-name)))
|
|
||||||
docs-list)))
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-enable-cache t
|
|
||||||
"Whether cache doc indices in memory."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'devdocs-browser)
|
|
||||||
|
|
||||||
(defvar devdocs-browser--docs-cache '() "Cached doc indices plist.")
|
|
||||||
|
|
||||||
(defun devdocs-browser--install-doc-internal (doc)
|
|
||||||
"(Re-)install doc identified by plist DOC. Return t if success."
|
|
||||||
(let* ((slug (plist-get doc :slug))
|
|
||||||
(mtime (plist-get doc :mtime))
|
|
||||||
(docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory))
|
|
||||||
(doc-dir (expand-file-name slug docs-dir))
|
|
||||||
success)
|
|
||||||
(unless (file-exists-p docs-dir)
|
|
||||||
(make-directory docs-dir t))
|
|
||||||
(when (file-exists-p doc-dir)
|
|
||||||
(delete-directory doc-dir t))
|
|
||||||
|
|
||||||
;; do not leave empty directory
|
|
||||||
(unwind-protect
|
|
||||||
(progn
|
|
||||||
(devdocs-browser--fetch-json
|
|
||||||
(format "docs/%s/index.json?%s" slug mtime)
|
|
||||||
(expand-file-name devdocs-browser--index-json-filename doc-dir))
|
|
||||||
(with-temp-file (expand-file-name devdocs-browser--metadata-filename doc-dir)
|
|
||||||
(print doc (current-buffer)))
|
|
||||||
(setq success t))
|
|
||||||
(unless success
|
|
||||||
(delete-directory doc-dir t)))
|
|
||||||
|
|
||||||
(if success
|
|
||||||
(message "Installed devdocs doc %s version %s" slug mtime)
|
|
||||||
(message "Failed to install devdocs doc %s" slug))
|
|
||||||
;; remove cache
|
|
||||||
(setq devdocs-browser--docs-cache
|
|
||||||
(plist-put devdocs-browser--docs-cache slug nil #'equal))
|
|
||||||
success))
|
|
||||||
|
|
||||||
(defun devdocs-browser--doc-readable-name (doc)
|
|
||||||
"Get human readable name for DOC."
|
|
||||||
(let ((slug (plist-get doc :slug))
|
|
||||||
(name (plist-get doc :name))
|
|
||||||
(version (plist-get doc :version))
|
|
||||||
(release (plist-get doc :release))
|
|
||||||
res)
|
|
||||||
(setq res (concat slug " (" name))
|
|
||||||
(unless (zerop (length version))
|
|
||||||
(setq res (concat res " " version)))
|
|
||||||
(unless (zerop (length release))
|
|
||||||
(setq res (concat res ", " release)))
|
|
||||||
(setq res (concat res ")"))
|
|
||||||
res))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-browser-install-doc (slug-or-name &optional force)
|
|
||||||
"Install doc by SLUG-OR-NAME.
|
|
||||||
When called interactively, user can choose from the list.
|
|
||||||
When called interactively with prefix, or FORCE is t, reinstall existing doc."
|
|
||||||
(interactive
|
|
||||||
(let* ((force current-prefix-arg)
|
|
||||||
(installed-docs
|
|
||||||
(devdocs-browser-list-installed-slugs))
|
|
||||||
(selected-slug
|
|
||||||
(devdocs-browser--completing-read
|
|
||||||
"Install doc"
|
|
||||||
(mapcar (lambda (doc)
|
|
||||||
(let ((slug (plist-get doc :slug)))
|
|
||||||
(unless (and (not force)
|
|
||||||
(member slug installed-docs))
|
|
||||||
(cons (devdocs-browser--doc-readable-name doc)
|
|
||||||
`(:value ,slug)))))
|
|
||||||
(devdocs-browser-list-docs)))))
|
|
||||||
(list selected-slug force)))
|
|
||||||
(let ((doc (devdocs-browser-find-doc slug-or-name)))
|
|
||||||
(unless (and (not force)
|
|
||||||
(member (plist-get doc :slug) (devdocs-browser-list-installed-slugs)))
|
|
||||||
(devdocs-browser--install-doc-internal doc))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-browser-uninstall-doc (slug)
|
|
||||||
"Uninstall doc by SLUG.
|
|
||||||
When called interactively, user can choose from the list."
|
|
||||||
(interactive (list (completing-read "Uninstall doc: "
|
|
||||||
(devdocs-browser-list-installed-slugs)
|
|
||||||
nil t)))
|
|
||||||
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory))
|
|
||||||
(doc-dir (expand-file-name slug docs-dir)))
|
|
||||||
(when (file-exists-p doc-dir)
|
|
||||||
(delete-directory doc-dir t)))
|
|
||||||
(setq devdocs-browser--docs-cache
|
|
||||||
(plist-put devdocs-browser--docs-cache slug nil #'equal)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--upgrade-readable-name (old-doc new-doc)
|
|
||||||
"Get human readable name for upgrade from OLD-DOC to NEW-DOC."
|
|
||||||
(let ((slug (plist-get old-doc :slug))
|
|
||||||
(name (plist-get old-doc :name))
|
|
||||||
(old-version (plist-get old-doc :version))
|
|
||||||
(old-release (plist-get old-doc :release))
|
|
||||||
(old-mtime (plist-get old-doc :mtime))
|
|
||||||
(new-version (plist-get new-doc :version))
|
|
||||||
(new-release (plist-get new-doc :release))
|
|
||||||
(new-mtime (plist-get new-doc :mtime))
|
|
||||||
res)
|
|
||||||
(setq res (format "%s (%s" slug name))
|
|
||||||
(unless (equal old-version new-version)
|
|
||||||
(setq res (concat res (format " %s->%s" old-version new-version))))
|
|
||||||
(unless (equal old-release new-release)
|
|
||||||
(setq res (concat res (format ", %s->%s" old-release new-release))))
|
|
||||||
(setq res (concat res (format ", %s->%s)" old-mtime new-mtime)))
|
|
||||||
res))
|
|
||||||
|
|
||||||
(defun devdocs-browser--upgrade-readable-name-or-nil (slug)
|
|
||||||
"Get human readable name for upgrading SLUG if it needs upgrade."
|
|
||||||
(let ((old-doc (devdocs-browser--load-doc slug))
|
|
||||||
(new-doc (devdocs-browser-find-doc slug)))
|
|
||||||
(when (and new-doc
|
|
||||||
(> (plist-get new-doc :mtime) (plist-get old-doc :mtime)))
|
|
||||||
(devdocs-browser--upgrade-readable-name old-doc new-doc))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-browser-upgrade-doc (slug)
|
|
||||||
"Upgrade doc by SLUG, return t if upgrade success.
|
|
||||||
Also download new version of offline data if
|
|
||||||
there's offline data for current version.
|
|
||||||
When called interactively, user can choose from list.
|
|
||||||
You may need to call `devdocs-browser-update-docs' first."
|
|
||||||
(interactive
|
|
||||||
(let (rows)
|
|
||||||
(dolist (slug (devdocs-browser-list-installed-slugs))
|
|
||||||
(let ((desc (devdocs-browser--upgrade-readable-name-or-nil slug)))
|
|
||||||
(when desc
|
|
||||||
(push (cons desc slug) rows))))
|
|
||||||
(if (null rows)
|
|
||||||
(progn
|
|
||||||
(message "All docs up to date")
|
|
||||||
(list nil))
|
|
||||||
(list
|
|
||||||
(cdr (assoc (completing-read "Upgrade doc: " rows nil t) rows))))))
|
|
||||||
(when (and slug (devdocs-browser--upgrade-readable-name-or-nil slug))
|
|
||||||
(let* ((has-offline-data (devdocs-browser-offline-data-dir slug))
|
|
||||||
(doc (devdocs-browser-find-doc slug))
|
|
||||||
(install-success (devdocs-browser--install-doc-internal doc)))
|
|
||||||
(when (and has-offline-data install-success)
|
|
||||||
(devdocs-browser--download-offline-data-internal doc))
|
|
||||||
install-success)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-browser-upgrade-all-docs ()
|
|
||||||
"Upgrade all docs."
|
|
||||||
(interactive)
|
|
||||||
(let ((count 0))
|
|
||||||
(dolist (slug (devdocs-browser-list-installed-slugs))
|
|
||||||
(message "Processing %s..." slug)
|
|
||||||
(when (devdocs-browser-upgrade-doc slug)
|
|
||||||
(setq count (1+ count))))
|
|
||||||
(message "Upgraded %s docs" count)))
|
|
||||||
|
|
||||||
(defun devdocs-browser-list-installed-slugs ()
|
|
||||||
"Get a list of installed docs' slug name."
|
|
||||||
(let ((dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory)))
|
|
||||||
(when (file-exists-p dir)
|
|
||||||
(directory-files dir nil
|
|
||||||
;; ignore ".", ".." and hidden files
|
|
||||||
"^[^.].*"))))
|
|
||||||
|
|
||||||
(defun devdocs-browser-find-installed-doc (slug-or-name)
|
|
||||||
"Find installed doc by SLUG-OR-NAME."
|
|
||||||
(let ((docs-list (mapcar #'devdocs-browser-installed-doc-info
|
|
||||||
(devdocs-browser-list-installed-slugs))))
|
|
||||||
(seq-find (lambda (doc)
|
|
||||||
(or (equal (plist-get doc :slug) slug-or-name)
|
|
||||||
(equal (plist-get doc :name) slug-or-name)))
|
|
||||||
docs-list)))
|
|
||||||
|
|
||||||
(defun devdocs-browser-installed-doc-info (slug)
|
|
||||||
"Get plist info of installed doc identified by SLUG."
|
|
||||||
(cddr (devdocs-browser--load-doc slug)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--load-doc (slug &optional refresh-cache)
|
|
||||||
"Load doc identified by SLUG, reload cache if REFRESH-CACHE is not nil.
|
|
||||||
Result is a plist metadata, with an extra :index field at the beginning."
|
|
||||||
(or (and (not refresh-cache) (plist-get devdocs-browser--docs-cache slug #'equal))
|
|
||||||
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir
|
|
||||||
devdocs-browser-data-directory))
|
|
||||||
(doc-dir (expand-file-name slug docs-dir))
|
|
||||||
(metadata-filename (expand-file-name devdocs-browser--metadata-filename doc-dir))
|
|
||||||
(metadata nil)
|
|
||||||
(index-filename (expand-file-name devdocs-browser--index-json-filename doc-dir))
|
|
||||||
(index (devdocs-browser--read-json index-filename))
|
|
||||||
res)
|
|
||||||
(when (file-exists-p metadata-filename)
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents metadata-filename)
|
|
||||||
(setq metadata (read (current-buffer))))
|
|
||||||
(setq res (append `(:index ,index) metadata))
|
|
||||||
(when devdocs-browser-enable-cache
|
|
||||||
(setq devdocs-browser--docs-cache
|
|
||||||
(plist-put devdocs-browser--docs-cache slug res #'equal))))
|
|
||||||
res)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--download-offline-data-internal (doc)
|
|
||||||
"(re-)Download and extract offline data for DOC."
|
|
||||||
(let* ((slug (plist-get doc :slug))
|
|
||||||
(mtime (plist-get doc :mtime))
|
|
||||||
(docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory))
|
|
||||||
(doc-dir (expand-file-name slug docs-dir))
|
|
||||||
(data-dir (expand-file-name devdocs-browser--offline-data-dir-name doc-dir))
|
|
||||||
success)
|
|
||||||
(unless (file-exists-p doc-dir)
|
|
||||||
(make-directory doc-dir t))
|
|
||||||
(when (file-exists-p data-dir)
|
|
||||||
(delete-directory data-dir t))
|
|
||||||
|
|
||||||
;; do not leave half-complete data directory
|
|
||||||
(unwind-protect
|
|
||||||
(let ((data (devdocs-browser--fetch-json
|
|
||||||
(format "%s/db.json?%s" slug mtime)
|
|
||||||
(expand-file-name devdocs-browser--offline-data-json-filename doc-dir)
|
|
||||||
devdocs-browser-doc-base-url)))
|
|
||||||
;; write data to files
|
|
||||||
(dolist (kv (seq-partition data 2))
|
|
||||||
(when-let* ((name (substring (symbol-name (car kv)) 1))
|
|
||||||
(value (cadr kv))
|
|
||||||
;; prepent "./" to fix paths starting with literal "~" (e.g. deno)
|
|
||||||
(path (expand-file-name (concat "./" name ".html") data-dir)))
|
|
||||||
(unless (file-exists-p (file-name-directory path))
|
|
||||||
(make-directory (file-name-directory path) t))
|
|
||||||
(write-region value nil path)))
|
|
||||||
(setq success t))
|
|
||||||
(unless success
|
|
||||||
(delete-directory data-dir t)))
|
|
||||||
|
|
||||||
(if success
|
|
||||||
(message "Installed devdocs offline data %s version %s" slug mtime)
|
|
||||||
(message "Failed to install devdocs offline data %s" slug))
|
|
||||||
|
|
||||||
success))
|
|
||||||
|
|
||||||
(defun devdocs-browser-offline-data-dir (slug)
|
|
||||||
"Return doc SLUG's offline data dir if present, return nil otherwise."
|
|
||||||
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-data-directory))
|
|
||||||
(doc-dir (expand-file-name slug docs-dir))
|
|
||||||
(data-dir (expand-file-name devdocs-browser--offline-data-dir-name doc-dir)))
|
|
||||||
(when (file-exists-p data-dir)
|
|
||||||
(file-name-as-directory data-dir))))
|
|
||||||
|
|
||||||
(defun devdocs-browser-download-offline-data (slug)
|
|
||||||
"Download offline data for doc SLUG.
|
|
||||||
Offline data contains full content pages,
|
|
||||||
which allows you to view docs without Internet connection.
|
|
||||||
It may take some time to download offline data.
|
|
||||||
When called interactively, user can choose from the list."
|
|
||||||
(interactive (list (completing-read
|
|
||||||
"Install offline data: "
|
|
||||||
(seq-filter
|
|
||||||
(lambda (slug) (null (devdocs-browser-offline-data-dir slug)))
|
|
||||||
(devdocs-browser-list-installed-slugs))
|
|
||||||
nil t)))
|
|
||||||
(when-let* ((doc (devdocs-browser--load-doc slug)))
|
|
||||||
(devdocs-browser--download-offline-data-internal doc)))
|
|
||||||
|
|
||||||
(defun devdocs-browser-remove-offline-data (slug)
|
|
||||||
"Remove offline data for doc SLUG.
|
|
||||||
When called interactively, user can choose from the list."
|
|
||||||
(interactive (list (completing-read
|
|
||||||
"Remove offline data: "
|
|
||||||
(seq-filter
|
|
||||||
#'devdocs-browser-offline-data-dir
|
|
||||||
(devdocs-browser-list-installed-slugs))
|
|
||||||
nil t)))
|
|
||||||
(when-let* ((data-dir (devdocs-browser-offline-data-dir slug)))
|
|
||||||
(delete-directory data-dir t)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--eww-open (doc path)
|
|
||||||
"Open PATH for document DOC using eww."
|
|
||||||
(let* ((slug (plist-get doc :slug))
|
|
||||||
(mtime (plist-get doc :mtime))
|
|
||||||
base-url url)
|
|
||||||
;; cannot use format directly because `path' may contains #query
|
|
||||||
;; path: hello/world#query
|
|
||||||
;; url for offline: file:///home/path/to/devdocs/python~3.8/hello/world.html#query
|
|
||||||
;; url for online: https://documents.devdocs.io/python~3.8/hello/world.html?161818817#query
|
|
||||||
(let ((offline-data-dir (devdocs-browser-offline-data-dir slug)))
|
|
||||||
(if offline-data-dir
|
|
||||||
(progn
|
|
||||||
(setq base-url (concat "file://" offline-data-dir))
|
|
||||||
(setq url (url-generic-parse-url (concat "file://" offline-data-dir path)))
|
|
||||||
(setf (url-filename url) (concat (url-filename url) ".html")))
|
|
||||||
(setq base-url (concat devdocs-browser-doc-base-url slug "/"))
|
|
||||||
(setq url (url-generic-parse-url
|
|
||||||
(concat devdocs-browser-doc-base-url slug "/" path)))
|
|
||||||
(setf (url-filename url)
|
|
||||||
(format "%s.html?%s" (url-filename url) mtime))))
|
|
||||||
|
|
||||||
(pop-to-buffer (format "*devdocs-%s*" slug))
|
|
||||||
(if devdocs-browser-eww-mode
|
|
||||||
(eww-save-history)
|
|
||||||
(eww-mode)
|
|
||||||
(devdocs-browser-eww-mode))
|
|
||||||
(setq-local devdocs-browser--eww-data
|
|
||||||
(list :doc doc
|
|
||||||
:base-url base-url))
|
|
||||||
|
|
||||||
(eww (url-recreate-url url))
|
|
||||||
(recenter)))
|
|
||||||
|
|
||||||
(defun devdocs-browser--default-active-slugs (&optional no-fallback-all)
|
|
||||||
"Default active doc slugs for current buffer, fallback to all slugs if not NO-FALLBACK-ALL."
|
|
||||||
(if devdocs-browser--eww-data
|
|
||||||
(list (plist-get (plist-get devdocs-browser--eww-data :doc) :slug))
|
|
||||||
(let ((names (or devdocs-browser-active-docs
|
|
||||||
(alist-get major-mode devdocs-browser-major-mode-docs-alist)))
|
|
||||||
slugs)
|
|
||||||
(dolist (name names)
|
|
||||||
(when-let* ((doc (devdocs-browser-find-installed-doc name))
|
|
||||||
(slug (plist-get doc :slug)))
|
|
||||||
(setq slugs (push slug slugs))))
|
|
||||||
(or slugs
|
|
||||||
(and (not no-fallback-all) (devdocs-browser-list-installed-slugs))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-browser-open-in (slug-or-name-list)
|
|
||||||
"Open entry in specified docs SLUG-OR-NAME-LIST.
|
|
||||||
When called interactively, user can choose from the list."
|
|
||||||
(interactive
|
|
||||||
(let ((def (devdocs-browser--default-active-slugs t)))
|
|
||||||
(list (completing-read-multiple
|
|
||||||
(concat "Select doc"
|
|
||||||
(when def (format " (default %s)" def))
|
|
||||||
": ")
|
|
||||||
(devdocs-browser-list-installed-slugs)
|
|
||||||
nil t nil nil def))))
|
|
||||||
|
|
||||||
(let ((current-word-regex
|
|
||||||
(when-let ((word (thing-at-point 'word t)))
|
|
||||||
(concat "\\<" (regexp-quote word) "\\>")))
|
|
||||||
(rows (make-hash-table :test 'equal))
|
|
||||||
slugs def)
|
|
||||||
(dolist (slug-or-name slug-or-name-list)
|
|
||||||
(when-let* ((doc-simple (devdocs-browser-find-installed-doc slug-or-name))
|
|
||||||
(slug (plist-get doc-simple :slug))
|
|
||||||
(doc (devdocs-browser--load-doc slug))
|
|
||||||
(index (plist-get doc :index))
|
|
||||||
(entries (plist-get index :entries)))
|
|
||||||
(setq slugs (push slug slugs))
|
|
||||||
(puthash (format "%s: INDEX PAGE" slug)
|
|
||||||
`(:value (,doc "index")
|
|
||||||
:group ,slug)
|
|
||||||
rows)
|
|
||||||
(seq-doseq (entry entries)
|
|
||||||
(let* ((name (plist-get entry :name))
|
|
||||||
(path (plist-get entry :path))
|
|
||||||
(type (plist-get entry :type))
|
|
||||||
(title (concat slug ": " name)))
|
|
||||||
(when (and (null def) current-word-regex)
|
|
||||||
(when (string-match-p current-word-regex name)
|
|
||||||
(setq def title)))
|
|
||||||
(puthash title `(:value (,doc ,path)
|
|
||||||
:group ,slug
|
|
||||||
:annotation ,type)
|
|
||||||
rows)))))
|
|
||||||
(let* ((selected-value
|
|
||||||
(devdocs-browser--completing-read
|
|
||||||
(format "Devdocs browser [%s]" (mapconcat #'identity slugs ","))
|
|
||||||
rows def)))
|
|
||||||
(when selected-value
|
|
||||||
(apply #'devdocs-browser--eww-open selected-value)))))
|
|
||||||
|
|
||||||
|
|
||||||
(defcustom devdocs-browser-open-fallback-to-all-docs t
|
|
||||||
"When not sure which docs to use, whether `devdocs-browser-open' should use all installed docs, or just ask the user to pick one (like `devdocs-browser-open-in')."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'devdocs-browser)
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun devdocs-browser-open ()
|
|
||||||
"Open entry in active docs.
|
|
||||||
Active docs are specified by `devdocs-browser-active-docs',
|
|
||||||
or `devdocs-browser-major-mode-docs-alist',
|
|
||||||
or the current doc type if called in a devdocs eww buffer.
|
|
||||||
When all of them are nil, all installed docs are used."
|
|
||||||
(interactive)
|
|
||||||
(if devdocs-browser-open-fallback-to-all-docs
|
|
||||||
(devdocs-browser-open-in (devdocs-browser--default-active-slugs))
|
|
||||||
(let ((slugs (devdocs-browser--default-active-slugs 'no-fallback-all)))
|
|
||||||
(if slugs
|
|
||||||
(devdocs-browser-open-in slugs)
|
|
||||||
(call-interactively 'devdocs-browser-open-in)))))
|
|
||||||
|
|
||||||
|
|
||||||
(provide 'devdocs-browser)
|
|
||||||
;;; devdocs-browser.el ends here
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
;;; dired-hacks-utils-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
|
||||||
|
;;
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(add-to-list 'load-path (directory-file-name
|
||||||
|
(or (file-name-directory #$) (car load-path))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;### (autoloads nil "dired-hacks-utils" "dired-hacks-utils.el"
|
||||||
|
;;;;;; (0 0 0 0))
|
||||||
|
;;; Generated autoloads from dired-hacks-utils.el
|
||||||
|
|
||||||
|
(register-definition-prefixes "dired-hacks-utils" '("dired-"))
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
|
;; Local Variables:
|
||||||
|
;; version-control: never
|
||||||
|
;; no-byte-compile: t
|
||||||
|
;; no-update-autoloads: t
|
||||||
|
;; coding: utf-8
|
||||||
|
;; End:
|
||||||
|
;;; dired-hacks-utils-autoloads.el ends here
|
|
@ -0,0 +1,2 @@
|
||||||
|
;;; Generated package description from dired-hacks-utils.el -*- no-byte-compile: t -*-
|
||||||
|
(define-package "dired-hacks-utils" "20221127.1247" "Utilities and helpers for dired-hacks collection" '((dash "2.5.0")) :commit "41d3eb42195d9f0894c20d18cc8e722b099aa1c1" :authors '(("Matúš Goljer" . "matus.goljer@gmail.com")) :maintainer '("Matúš Goljer" . "matus.goljer@gmail.com") :keywords '("files"))
|
275
code/elpa/dired-hacks-utils-20221127.1247/dired-hacks-utils.el
Normal file
275
code/elpa/dired-hacks-utils-20221127.1247/dired-hacks-utils.el
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
;;; dired-hacks-utils.el --- Utilities and helpers for dired-hacks collection
|
||||||
|
|
||||||
|
;; Copyright (C) 2014-2015 Matúš Goljer
|
||||||
|
|
||||||
|
;; Author: Matúš Goljer <matus.goljer@gmail.com>
|
||||||
|
;; Maintainer: Matúš Goljer <matus.goljer@gmail.com>
|
||||||
|
;; Keywords: files
|
||||||
|
;; Package-Version: 20221127.1247
|
||||||
|
;; Package-Commit: 41d3eb42195d9f0894c20d18cc8e722b099aa1c1
|
||||||
|
;; Version: 0.0.1
|
||||||
|
;; Created: 14th February 2014
|
||||||
|
;; Package-Requires: ((dash "2.5.0"))
|
||||||
|
|
||||||
|
;; This program is free software; you can redistribute it and/or modify
|
||||||
|
;; it under the terms of the GNU General Public License as published by
|
||||||
|
;; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
;; (at your option) any later version.
|
||||||
|
|
||||||
|
;; This program is distributed in the hope that it will be useful,
|
||||||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;; GNU General Public License for more details.
|
||||||
|
|
||||||
|
;; You should have received a copy of the GNU General Public License
|
||||||
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Utilities and helpers for `dired-hacks' collection of dired
|
||||||
|
;; improvements.
|
||||||
|
|
||||||
|
;; This package also provides these interactive functions:
|
||||||
|
;; * `dired-hacks-next-file' - go to next file, skipping empty and non-file lines
|
||||||
|
;; * `dired-hacks-previous-file' - go to previous file, skipping empty
|
||||||
|
;; and non-file lines
|
||||||
|
;; * `dired-utils-format-information-line-mode' - Format the information
|
||||||
|
;; (summary) line file sizes to be human readable (e.g. 1GB instead of 1048576).
|
||||||
|
|
||||||
|
|
||||||
|
;; See https://github.com/Fuco1/dired-hacks for the entire collection
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'dash)
|
||||||
|
(require 'dired)
|
||||||
|
|
||||||
|
(defgroup dired-hacks ()
|
||||||
|
"Collection of useful dired additions."
|
||||||
|
:group 'dired
|
||||||
|
:prefix "dired-hacks-")
|
||||||
|
|
||||||
|
(defcustom dired-hacks-file-size-formatter 'file-size-human-readable
|
||||||
|
"The function used to format file sizes.
|
||||||
|
|
||||||
|
See `dired-utils-format-file-sizes'."
|
||||||
|
:type 'symbol
|
||||||
|
:group 'dired-hacks)
|
||||||
|
|
||||||
|
(defcustom dired-hacks-datetime-regexp
|
||||||
|
"\\sw\\sw\\sw....\\(?:[0-9][0-9]:[0-9][0-9]\\|.[0-9]\\{4\\}\\)"
|
||||||
|
"A regexp matching the date/time in the dired listing.
|
||||||
|
|
||||||
|
It is used to determine where the filename starts. It should
|
||||||
|
*not* match any characters after the last character of the
|
||||||
|
timestamp. It is assumed that the timestamp is preceded and
|
||||||
|
followed by at least one space character. You should only use
|
||||||
|
shy groups (prefixed with ?:) because the first group is used by
|
||||||
|
the font-lock to determine what portion of the name should be
|
||||||
|
colored."
|
||||||
|
:type 'string
|
||||||
|
:group 'dired-hacks)
|
||||||
|
|
||||||
|
(defalias 'dired-utils--string-trim
|
||||||
|
(if (and (require 'subr-x nil t)
|
||||||
|
(fboundp 'string-trim))
|
||||||
|
#'string-trim
|
||||||
|
(lambda (string)
|
||||||
|
(let ((s string))
|
||||||
|
(when (string-match "\\`[ \t\n\r]+" s)
|
||||||
|
(setq s (replace-match "" t t s)))
|
||||||
|
(when (string-match "[ \t\n\r]+\\'" s)
|
||||||
|
(setq s (replace-match "" t t s)))
|
||||||
|
s)))
|
||||||
|
"Trim STRING of trailing whitespace.
|
||||||
|
|
||||||
|
\(fn STRING)")
|
||||||
|
|
||||||
|
(defun dired-utils-get-filename (&optional localp)
|
||||||
|
"Like `dired-get-filename' but never signal an error.
|
||||||
|
|
||||||
|
Optional arg LOCALP with value `no-dir' means don't include
|
||||||
|
directory name in result."
|
||||||
|
(dired-get-filename localp t))
|
||||||
|
|
||||||
|
(defun dired-utils-get-all-files (&optional localp)
|
||||||
|
"Return all files in this dired buffer as a list.
|
||||||
|
|
||||||
|
LOCALP has same semantics as in `dired-get-filename'."
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(let (r)
|
||||||
|
(while (= 0 (forward-line))
|
||||||
|
(--when-let (dired-utils-get-filename localp)
|
||||||
|
(push it r)))
|
||||||
|
(nreverse r))))
|
||||||
|
|
||||||
|
(defconst dired-utils-file-attributes-keywords
|
||||||
|
'(:isdir :nlinks :uid :gid :atime :mtime :ctime :size :modes :gidchg :inode :devnum)
|
||||||
|
"List of keywords to map with `file-attributes'.")
|
||||||
|
|
||||||
|
(defconst dired-utils-info-keywords
|
||||||
|
`(:name :issym :target ,@dired-utils-file-attributes-keywords)
|
||||||
|
"List of keywords available for `dired-utils-get-info'.")
|
||||||
|
|
||||||
|
(defun dired-utils--get-keyword-info (keyword)
|
||||||
|
"Get file information about KEYWORD."
|
||||||
|
(let ((filename (dired-utils-get-filename)))
|
||||||
|
(cl-case keyword
|
||||||
|
(:name filename)
|
||||||
|
(:isdir (file-directory-p filename))
|
||||||
|
(:issym (and (file-symlink-p filename) t))
|
||||||
|
(:target (file-symlink-p filename))
|
||||||
|
(t
|
||||||
|
(nth (-elem-index keyword dired-utils-file-attributes-keywords)
|
||||||
|
(file-attributes filename))))))
|
||||||
|
|
||||||
|
(defun dired-utils-get-info (&rest keywords)
|
||||||
|
"Query for info about the file at point.
|
||||||
|
|
||||||
|
KEYWORDS is a list of attributes to query.
|
||||||
|
|
||||||
|
When querying for one attribute, its value is returned. When
|
||||||
|
querying for more than one, a list of results is returned.
|
||||||
|
|
||||||
|
The available keywords are listed in
|
||||||
|
`dired-utils-info-keywords'."
|
||||||
|
(let ((attributes (mapcar 'dired-utils--get-keyword-info keywords)))
|
||||||
|
(if (> (length attributes) 1)
|
||||||
|
attributes
|
||||||
|
(car attributes))))
|
||||||
|
|
||||||
|
(defun dired-utils-goto-line (filename)
|
||||||
|
"Go to line describing FILENAME in listing.
|
||||||
|
|
||||||
|
Should be absolute file name matched against
|
||||||
|
`dired-get-filename'."
|
||||||
|
(goto-char (point-min))
|
||||||
|
(let (stop)
|
||||||
|
(while (and (not stop)
|
||||||
|
(= (forward-line) 0))
|
||||||
|
(when (equal filename (dired-utils-get-filename))
|
||||||
|
(setq stop t)
|
||||||
|
(dired-move-to-filename)))
|
||||||
|
stop))
|
||||||
|
|
||||||
|
(defun dired-utils-match-filename-regexp (filename alist)
|
||||||
|
"Match FILENAME against each car in ALIST and return first matched cons.
|
||||||
|
|
||||||
|
Each car in ALIST is a regular expression.
|
||||||
|
|
||||||
|
The matching is done using `string-match-p'."
|
||||||
|
(let (match)
|
||||||
|
(--each-while alist (not match)
|
||||||
|
(when (string-match-p (car it) filename)
|
||||||
|
(setq match it)))
|
||||||
|
match))
|
||||||
|
|
||||||
|
(defun dired-utils-match-filename-extension (filename alist)
|
||||||
|
"Match FILENAME against each car in ALIST and return first matched cons.
|
||||||
|
|
||||||
|
Each car in ALIST is a string representing file extension
|
||||||
|
*without* the delimiting dot."
|
||||||
|
(let (done)
|
||||||
|
(--each-while alist (not done)
|
||||||
|
(when (string-match-p (concat "\\." (regexp-quote (car it)) "\\'") filename)
|
||||||
|
(setq done it)))
|
||||||
|
done))
|
||||||
|
|
||||||
|
(defun dired-utils-format-information-line ()
|
||||||
|
"Format the disk space on the Dired information line."
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(forward-line)
|
||||||
|
(let ((inhibit-read-only t)
|
||||||
|
(limit (line-end-position)))
|
||||||
|
(while (re-search-forward "\\(?:directory\\|available\\) \\(\\<[0-9]+$\\>\\)" nil t)
|
||||||
|
(replace-match
|
||||||
|
(save-match-data
|
||||||
|
(propertize (dired-utils--string-trim
|
||||||
|
(funcall dired-hacks-file-size-formatter
|
||||||
|
(* 1024 (string-to-number (match-string 1))) t))
|
||||||
|
'invisible 'dired-hide-details-information))
|
||||||
|
t nil nil 1)))))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Predicates
|
||||||
|
(defun dired-utils-is-file-p ()
|
||||||
|
"Return non-nil if the line at point is a file or a directory."
|
||||||
|
(dired-utils-get-filename 'no-dir))
|
||||||
|
|
||||||
|
(defun dired-utils-is-dir-p ()
|
||||||
|
"Return non-nil if the line at point is a directory."
|
||||||
|
(--when-let (dired-utils-get-filename)
|
||||||
|
(file-directory-p it)))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Interactive
|
||||||
|
;; TODO: add wrap-around option
|
||||||
|
(defun dired-hacks-next-file (&optional arg)
|
||||||
|
"Move point to the next file.
|
||||||
|
|
||||||
|
Optional prefix ARG says how many lines to move; default is one
|
||||||
|
line."
|
||||||
|
(interactive "p")
|
||||||
|
(unless arg (setq arg 1))
|
||||||
|
(if (< arg 0)
|
||||||
|
(dired-hacks-previous-file (- arg))
|
||||||
|
(--dotimes arg
|
||||||
|
(forward-line)
|
||||||
|
(while (and (or (not (dired-utils-is-file-p))
|
||||||
|
(get-text-property (point) 'invisible))
|
||||||
|
(= (forward-line) 0))))
|
||||||
|
(if (not (= (point) (point-max)))
|
||||||
|
(dired-move-to-filename)
|
||||||
|
(forward-line -1)
|
||||||
|
(dired-move-to-filename)
|
||||||
|
nil)))
|
||||||
|
|
||||||
|
(defun dired-hacks-previous-file (&optional arg)
|
||||||
|
"Move point to the previous file.
|
||||||
|
|
||||||
|
Optional prefix ARG says how many lines to move; default is one
|
||||||
|
line."
|
||||||
|
(interactive "p")
|
||||||
|
(unless arg (setq arg 1))
|
||||||
|
(if (< arg 0)
|
||||||
|
(dired-hacks-next-file (- arg))
|
||||||
|
(--dotimes arg
|
||||||
|
(forward-line -1)
|
||||||
|
(while (and (or (not (dired-utils-is-file-p))
|
||||||
|
(get-text-property (point) 'invisible))
|
||||||
|
(= (forward-line -1) 0))))
|
||||||
|
(if (not (= (point) (point-min)))
|
||||||
|
(dired-move-to-filename)
|
||||||
|
(dired-hacks-next-file)
|
||||||
|
nil)))
|
||||||
|
|
||||||
|
(defun dired-hacks-compare-files (file-a file-b)
|
||||||
|
"Test if two files FILE-A and FILE-B are the (probably) the same."
|
||||||
|
(interactive (let ((other-dir (dired-dwim-target-directory)))
|
||||||
|
(list (read-file-name "File A: " default-directory (car (dired-get-marked-files)) t)
|
||||||
|
(read-file-name "File B: " other-dir (with-current-buffer (cdr (assoc other-dir dired-buffers))
|
||||||
|
(car (dired-get-marked-files))) t))))
|
||||||
|
(let ((md5-a (with-temp-buffer
|
||||||
|
(shell-command (format "md5sum %s" file-a) (current-buffer))
|
||||||
|
(buffer-string)))
|
||||||
|
(md5-b (with-temp-buffer
|
||||||
|
(shell-command (format "md5sum %s" file-b) (current-buffer))
|
||||||
|
(buffer-string))))
|
||||||
|
(message "%s%sFiles are %s." md5-a md5-b
|
||||||
|
(if (equal (car (split-string md5-a))
|
||||||
|
(car (split-string md5-b)))
|
||||||
|
"probably the same" "different"))))
|
||||||
|
|
||||||
|
(define-minor-mode dired-utils-format-information-line-mode
|
||||||
|
"Toggle formatting of disk space in the Dired information line."
|
||||||
|
:group 'dired-utils
|
||||||
|
:lighter ""
|
||||||
|
(if dired-utils-format-information-line-mode
|
||||||
|
(add-hook 'dired-after-readin-hook #'dired-utils-format-information-line)
|
||||||
|
(remove-hook 'dired-after-readin-hook #'dired-utils-format-information-line)))
|
||||||
|
|
||||||
|
(provide 'dired-hacks-utils)
|
||||||
|
|
||||||
|
;;; dired-hacks-utils.el ends here
|
|
@ -0,0 +1,27 @@
|
||||||
|
;;; dired-hacks-utils-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
|
||||||
|
;;
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(add-to-list 'load-path (directory-file-name
|
||||||
|
(or (file-name-directory #$) (car load-path))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;### (autoloads nil "dired-hacks-utils" "dired-hacks-utils.el"
|
||||||
|
;;;;;; (0 0 0 0))
|
||||||
|
;;; Generated autoloads from dired-hacks-utils.el
|
||||||
|
|
||||||
|
(register-definition-prefixes "dired-hacks-utils" '("dired-"))
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
|
;;;### (autoloads nil nil ("dired-hacks-utils-pkg.el") (0 0 0 0))
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
|
;; Local Variables:
|
||||||
|
;; version-control: never
|
||||||
|
;; no-byte-compile: t
|
||||||
|
;; no-update-autoloads: t
|
||||||
|
;; coding: utf-8
|
||||||
|
;; End:
|
||||||
|
;;; dired-hacks-utils-autoloads.el ends here
|
|
@ -1,15 +1,13 @@
|
||||||
(define-package "dired-hacks-utils" "20240629.1906" "Utilities and helpers for dired-hacks collection"
|
(define-package "dired-hacks-utils" "20230512.1107" "Utilities and helpers for dired-hacks collection"
|
||||||
'((dash "2.5.0")
|
'((dash "2.5.0"))
|
||||||
(emacs "24.3"))
|
:commit "523f51b4152a3bf4e60fe57f512732c698b5c96f" :authors
|
||||||
:commit "63b04d17936c98cb4ad7ce6bc3331cda8e30c55a" :authors
|
|
||||||
'(("Matúš Goljer" . "matus.goljer@gmail.com"))
|
'(("Matúš Goljer" . "matus.goljer@gmail.com"))
|
||||||
:maintainers
|
:maintainers
|
||||||
'(("Matúš Goljer" . "matus.goljer@gmail.com"))
|
'(("Matúš Goljer" . "matus.goljer@gmail.com"))
|
||||||
:maintainer
|
:maintainer
|
||||||
'("Matúš Goljer" . "matus.goljer@gmail.com")
|
'("Matúš Goljer" . "matus.goljer@gmail.com")
|
||||||
:keywords
|
:keywords
|
||||||
'("files")
|
'("files"))
|
||||||
:url "https://github.com/Fuco1/dired-hacks")
|
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
;; no-byte-compile: t
|
;; no-byte-compile: t
|
||||||
;; End:
|
;; End:
|
|
@ -7,8 +7,7 @@
|
||||||
;; Keywords: files
|
;; Keywords: files
|
||||||
;; Version: 0.0.1
|
;; Version: 0.0.1
|
||||||
;; Created: 14th February 2014
|
;; Created: 14th February 2014
|
||||||
;; Package-Requires: ((dash "2.5.0") (emacs "24.3"))
|
;; Package-Requires: ((dash "2.5.0"))
|
||||||
;; URL: https://github.com/Fuco1/dired-hacks
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
;; This program is free software; you can redistribute it and/or modify
|
||||||
;; it under the terms of the GNU General Public License as published by
|
;; it under the terms of the GNU General Public License as published by
|
||||||
|
@ -42,7 +41,6 @@
|
||||||
|
|
||||||
(require 'dash)
|
(require 'dash)
|
||||||
(require 'dired)
|
(require 'dired)
|
||||||
(require 'dired-aux) ;; for dired-dwim-target-directory
|
|
||||||
|
|
||||||
(defgroup dired-hacks ()
|
(defgroup dired-hacks ()
|
||||||
"Collection of useful dired additions."
|
"Collection of useful dired additions."
|
|
@ -1,28 +0,0 @@
|
||||||
;;; dired-hacks-utils-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
|
|
||||||
;; Generated by the `loaddefs-generate' function.
|
|
||||||
|
|
||||||
;; This file is part of GNU Emacs.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; Generated autoloads from dired-hacks-utils.el
|
|
||||||
|
|
||||||
(register-definition-prefixes "dired-hacks-utils" '("dired-"))
|
|
||||||
|
|
||||||
;;; End of scraped data
|
|
||||||
|
|
||||||
(provide 'dired-hacks-utils-autoloads)
|
|
||||||
|
|
||||||
;; Local Variables:
|
|
||||||
;; version-control: never
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; no-update-autoloads: t
|
|
||||||
;; no-native-compile: t
|
|
||||||
;; coding: utf-8-emacs-unix
|
|
||||||
;; End:
|
|
||||||
|
|
||||||
;;; dired-hacks-utils-autoloads.el ends here
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
;;; dired-rainbow-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
|
||||||
|
;;
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(add-to-list 'load-path (directory-file-name
|
||||||
|
(or (file-name-directory #$) (car load-path))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;### (autoloads nil "dired-rainbow" "dired-rainbow.el" (0 0 0 0))
|
||||||
|
;;; Generated autoloads from dired-rainbow.el
|
||||||
|
|
||||||
|
(register-definition-prefixes "dired-rainbow" '("dired-rainbow-"))
|
||||||
|
|
||||||
|
;;;***
|
||||||
|
|
||||||
|
;; Local Variables:
|
||||||
|
;; version-control: never
|
||||||
|
;; no-byte-compile: t
|
||||||
|
;; no-update-autoloads: t
|
||||||
|
;; coding: utf-8
|
||||||
|
;; End:
|
||||||
|
;;; dired-rainbow-autoloads.el ends here
|
|
@ -0,0 +1,2 @@
|
||||||
|
;;; Generated package description from dired-rainbow.el -*- no-byte-compile: t -*-
|
||||||
|
(define-package "dired-rainbow" "20221127.1247" "Extended file highlighting according to its type" '((dash "2.5.0") (dired-hacks-utils "0.0.1")) :commit "41d3eb42195d9f0894c20d18cc8e722b099aa1c1" :authors '(("Matus Goljer" . "matus.goljer@gmail.com")) :maintainer '("Matus Goljer" . "matus.goljer@gmail.com") :keywords '("files"))
|
|
@ -5,10 +5,12 @@
|
||||||
;; Author: Matus Goljer <matus.goljer@gmail.com>
|
;; Author: Matus Goljer <matus.goljer@gmail.com>
|
||||||
;; Maintainer: Matus Goljer <matus.goljer@gmail.com>
|
;; Maintainer: Matus Goljer <matus.goljer@gmail.com>
|
||||||
;; Keywords: files
|
;; Keywords: files
|
||||||
|
;; Package-Commit: 41d3eb42195d9f0894c20d18cc8e722b099aa1c1
|
||||||
|
;; Package-Version: 20221127.1247
|
||||||
|
;; Package-X-Original-Version: 20170922.817
|
||||||
;; Version: 0.0.3
|
;; Version: 0.0.3
|
||||||
;; Created: 16th February 2014
|
;; Created: 16th February 2014
|
||||||
;; Package-Requires: ((dash "2.5.0") (dired-hacks-utils "0.0.1") (emacs "24"))
|
;; Package-Requires: ((dash "2.5.0") (dired-hacks-utils "0.0.1"))
|
||||||
;; URL: https://github.com/Fuco1/dired-hacks
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
;; This program is free software; you can redistribute it and/or modify
|
||||||
;; it under the terms of the GNU General Public License as published by
|
;; it under the terms of the GNU General Public License as published by
|
|
@ -1,28 +0,0 @@
|
||||||
;;; dired-rainbow-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
|
|
||||||
;; Generated by the `loaddefs-generate' function.
|
|
||||||
|
|
||||||
;; This file is part of GNU Emacs.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; Generated autoloads from dired-rainbow.el
|
|
||||||
|
|
||||||
(register-definition-prefixes "dired-rainbow" '("dired-rainbow-"))
|
|
||||||
|
|
||||||
;;; End of scraped data
|
|
||||||
|
|
||||||
(provide 'dired-rainbow-autoloads)
|
|
||||||
|
|
||||||
;; Local Variables:
|
|
||||||
;; version-control: never
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; no-update-autoloads: t
|
|
||||||
;; no-native-compile: t
|
|
||||||
;; coding: utf-8-emacs-unix
|
|
||||||
;; End:
|
|
||||||
|
|
||||||
;;; dired-rainbow-autoloads.el ends here
|
|
|
@ -1,16 +0,0 @@
|
||||||
(define-package "dired-rainbow" "20240629.1857" "Extended file highlighting according to its type"
|
|
||||||
'((dash "2.5.0")
|
|
||||||
(dired-hacks-utils "0.0.1")
|
|
||||||
(emacs "24"))
|
|
||||||
:commit "d1a85901c892ba7ec273995070a43cbbbe5d0b37" :authors
|
|
||||||
'(("Matus Goljer" . "matus.goljer@gmail.com"))
|
|
||||||
:maintainers
|
|
||||||
'(("Matus Goljer" . "matus.goljer@gmail.com"))
|
|
||||||
:maintainer
|
|
||||||
'("Matus Goljer" . "matus.goljer@gmail.com")
|
|
||||||
:keywords
|
|
||||||
'("files")
|
|
||||||
:url "https://github.com/Fuco1/dired-hacks")
|
|
||||||
;; Local Variables:
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; End:
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
(define-package "dockerfile-mode" "20240318.24" "Major mode for editing Docker's Dockerfiles"
|
||||||
|
'((emacs "24")
|
||||||
|
(s "1.2.0"))
|
||||||
|
:commit "f6196726342b44081933597a343805db6366e7ac" :keywords
|
||||||
|
'("docker" "languages" "processes" "tools")
|
||||||
|
:url "https://github.com/spotify/dockerfile-mode")
|
||||||
|
;; Local Variables:
|
||||||
|
;; no-byte-compile: t
|
||||||
|
;; End:
|
|
@ -1,7 +1,7 @@
|
||||||
;;; dockerfile-mode.el --- Major mode for editing Docker's Dockerfiles -*- lexical-binding: t -*-
|
;;; dockerfile-mode.el --- Major mode for editing Docker's Dockerfiles -*- lexical-binding: t -*-
|
||||||
|
|
||||||
;; Copyright (c) 2013 Spotify AB
|
;; Copyright (c) 2013 Spotify AB
|
||||||
;; Package-Requires: ((emacs "24"))
|
;; Package-Requires: ((emacs "24") (s "1.2.0"))
|
||||||
;; Homepage: https://github.com/spotify/dockerfile-mode
|
;; Homepage: https://github.com/spotify/dockerfile-mode
|
||||||
;; URL: https://github.com/spotify/dockerfile-mode
|
;; URL: https://github.com/spotify/dockerfile-mode
|
||||||
;; Version: 1.7
|
;; Version: 1.7
|
||||||
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
(require 'sh-script)
|
(require 'sh-script)
|
||||||
(require 'rx)
|
(require 'rx)
|
||||||
|
(require 's)
|
||||||
|
|
||||||
|
|
||||||
(declare-function cygwin-convert-file-name-to-windows "cygw32.c" (file &optional absolute-p))
|
(declare-function cygwin-convert-file-name-to-windows "cygw32.c" (file &optional absolute-p))
|
||||||
|
@ -165,7 +166,7 @@ by `dockerfile-enable-auto-indent'."
|
||||||
|
|
||||||
(defun dockerfile-build-arg-string ()
|
(defun dockerfile-build-arg-string ()
|
||||||
"Create a --build-arg string for each element in `dockerfile-build-args'."
|
"Create a --build-arg string for each element in `dockerfile-build-args'."
|
||||||
(mapconcat (lambda (arg) (concat "--build-arg=" (replace-regexp-in-string "\\\\=" "=" (shell-quote-argument arg))))
|
(mapconcat (lambda (arg) (concat "--build-arg=" (s-replace "\\=" "=" (shell-quote-argument arg))))
|
||||||
dockerfile-build-args " "))
|
dockerfile-build-args " "))
|
||||||
|
|
||||||
(defun dockerfile-standard-filename (file)
|
(defun dockerfile-standard-filename (file)
|
|
@ -1,8 +0,0 @@
|
||||||
(define-package "dockerfile-mode" "20240324.1010" "Major mode for editing Docker's Dockerfiles"
|
|
||||||
'((emacs "24"))
|
|
||||||
:commit "39a012a27fcf6fb629c447d13b6974baf906714c" :keywords
|
|
||||||
'("docker" "languages" "processes" "tools")
|
|
||||||
:url "https://github.com/spotify/dockerfile-mode")
|
|
||||||
;; Local Variables:
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; End:
|
|
|
@ -1,68 +0,0 @@
|
||||||
;;; focus-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
|
|
||||||
;; Generated by the `loaddefs-generate' function.
|
|
||||||
|
|
||||||
;; This file is part of GNU Emacs.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; Generated autoloads from focus.el
|
|
||||||
|
|
||||||
(autoload 'focus-mode "focus" "\
|
|
||||||
Dim the font color of text in surrounding sections.
|
|
||||||
|
|
||||||
This is a minor mode. If called interactively, toggle the `Focus
|
|
||||||
mode' mode. If the prefix argument is positive, enable the mode,
|
|
||||||
and if it is zero or negative, disable the mode.
|
|
||||||
|
|
||||||
If called from Lisp, toggle the mode if ARG is `toggle'. Enable
|
|
||||||
the mode if ARG is nil, omitted, or is a positive number.
|
|
||||||
Disable the mode if ARG is a negative number.
|
|
||||||
|
|
||||||
To check whether the minor mode is enabled in the current buffer,
|
|
||||||
evaluate `focus-mode'.
|
|
||||||
|
|
||||||
The mode's hook is called both when the mode is enabled and when
|
|
||||||
it is disabled.
|
|
||||||
|
|
||||||
\\{focus-mode-map}
|
|
||||||
|
|
||||||
(fn &optional ARG)" t)
|
|
||||||
(autoload 'focus-read-only-mode "focus" "\
|
|
||||||
A read-only mode optimized for `focus-mode'.
|
|
||||||
|
|
||||||
This is a minor mode. If called interactively, toggle the
|
|
||||||
`Focus-Read-Only mode' mode. If the prefix argument is positive,
|
|
||||||
enable the mode, and if it is zero or negative, disable the mode.
|
|
||||||
|
|
||||||
If called from Lisp, toggle the mode if ARG is `toggle'. Enable
|
|
||||||
the mode if ARG is nil, omitted, or is a positive number.
|
|
||||||
Disable the mode if ARG is a negative number.
|
|
||||||
|
|
||||||
To check whether the minor mode is enabled in the current buffer,
|
|
||||||
evaluate `focus-read-only-mode'.
|
|
||||||
|
|
||||||
The mode's hook is called both when the mode is enabled and when
|
|
||||||
it is disabled.
|
|
||||||
|
|
||||||
\\{focus-read-only-mode-map}
|
|
||||||
|
|
||||||
(fn &optional ARG)" t)
|
|
||||||
(register-definition-prefixes "focus" '("focus-"))
|
|
||||||
|
|
||||||
;;; End of scraped data
|
|
||||||
|
|
||||||
(provide 'focus-autoloads)
|
|
||||||
|
|
||||||
;; Local Variables:
|
|
||||||
;; version-control: never
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; no-update-autoloads: t
|
|
||||||
;; no-native-compile: t
|
|
||||||
;; coding: utf-8-emacs-unix
|
|
||||||
;; End:
|
|
||||||
|
|
||||||
;;; focus-autoloads.el ends here
|
|
|
@ -1,13 +0,0 @@
|
||||||
(define-package "focus" "20240528.901" "Dim the font color of text in surrounding sections"
|
|
||||||
'((emacs "24.3")
|
|
||||||
(cl-lib "0.5"))
|
|
||||||
:commit "17c471544f540f2cf9a05fd6cd87e52e5de317e2" :authors
|
|
||||||
'(("Lars Tveito" . "larstvei@ifi.uio.no"))
|
|
||||||
:maintainers
|
|
||||||
'(("Lars Tveito" . "larstvei@ifi.uio.no"))
|
|
||||||
:maintainer
|
|
||||||
'("Lars Tveito" . "larstvei@ifi.uio.no")
|
|
||||||
:url "http://github.com/larstvei/Focus")
|
|
||||||
;; Local Variables:
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; End:
|
|
|
@ -1,329 +0,0 @@
|
||||||
;;; focus.el --- Dim the font color of text in surrounding sections -*- lexical-binding: t; -*-
|
|
||||||
|
|
||||||
;; Copyright (C) 2015 Lars Tveito
|
|
||||||
|
|
||||||
;; Author: Lars Tveito <larstvei@ifi.uio.no>
|
|
||||||
;; URL: http://github.com/larstvei/Focus
|
|
||||||
;; Created: 11th May 2015
|
|
||||||
;; Version: 1.0.1
|
|
||||||
;; Package-Requires: ((emacs "24.3") (cl-lib "0.5"))
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
|
||||||
;; it under the terms of the GNU General Public License as published by
|
|
||||||
;; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
|
|
||||||
;; This program is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
;; GNU General Public License for more details.
|
|
||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Focus provides `focus-mode` that dims the text of surrounding sections,
|
|
||||||
;; similar to [iA Writer's](https://ia.net/writer) Focus Mode.
|
|
||||||
;;
|
|
||||||
;; Enable the mode with `M-x focus-mode'.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'thingatpt)
|
|
||||||
|
|
||||||
(defgroup focus ()
|
|
||||||
"Dim the font color of text in surrounding sections."
|
|
||||||
:group 'font-lock
|
|
||||||
:prefix "focus-")
|
|
||||||
|
|
||||||
(defcustom focus-mode-to-thing '((prog-mode . defun)
|
|
||||||
(text-mode . paragraph)
|
|
||||||
(org-mode . org-element))
|
|
||||||
"An associated list between mode and thing.
|
|
||||||
|
|
||||||
A thing is defined in thingatpt.el; the thing determines the
|
|
||||||
narrowness of the focused section.
|
|
||||||
|
|
||||||
Note that the order of the list matters. The first mode that the
|
|
||||||
current mode is derived from is used, so more modes that have
|
|
||||||
many derivatives should be placed by the end of the list.
|
|
||||||
|
|
||||||
Things that are defined include `symbol', `list', `sexp',
|
|
||||||
`defun', `filename', `url', `email', `word', `sentence',
|
|
||||||
`whitespace', `line', and `page'.
|
|
||||||
|
|
||||||
In order for changes to take effect, reenable `focus-mode'."
|
|
||||||
:type '(alist :key-type symbol :valye-type symbol)
|
|
||||||
:group 'focus)
|
|
||||||
|
|
||||||
(defcustom focus-read-only-blink-seconds 1
|
|
||||||
"The duration of a cursor blink in `focus-read-only-mode'."
|
|
||||||
:type 'number
|
|
||||||
:group 'focus)
|
|
||||||
|
|
||||||
(defcustom focus-update-idle-delay nil
|
|
||||||
"Delay (in seconds) before updating the focus after each command.
|
|
||||||
The default value of nil results in an immediate update.
|
|
||||||
Increase this value if you experience performance issues."
|
|
||||||
:type '(choice (const :tag "Immediate update" nil)
|
|
||||||
(const :tag "Delayed update (0.1s)" 0.1)
|
|
||||||
(number :tag "Custom delay"))
|
|
||||||
:group 'focus)
|
|
||||||
|
|
||||||
(defface focus-unfocused
|
|
||||||
'((t :inherit shadow))
|
|
||||||
"The face that overlays the unfocused area."
|
|
||||||
:group 'focus)
|
|
||||||
|
|
||||||
(defface focus-focused nil
|
|
||||||
"The face that overlays the focused area."
|
|
||||||
:group 'focus)
|
|
||||||
|
|
||||||
(defvar focus-cursor-type cursor-type
|
|
||||||
"Used to restore the users `cursor-type'.")
|
|
||||||
|
|
||||||
(defvar-local focus-current-thing nil
|
|
||||||
"Overrides the choice of thing dictated by `focus-mode-to-thing' if set.")
|
|
||||||
|
|
||||||
(defvar-local focus-current-thing-cache nil
|
|
||||||
"Caches the current thing to focus.")
|
|
||||||
|
|
||||||
(defvar-local focus-buffer nil
|
|
||||||
"Local reference to the buffer focus functions operate on.")
|
|
||||||
|
|
||||||
(defvar-local focus-pre-overlay nil
|
|
||||||
"The overlay that dims the text prior to the current-point.")
|
|
||||||
|
|
||||||
(defvar-local focus-mid-overlay nil
|
|
||||||
"The overlay that surrounds the text of the current-point.")
|
|
||||||
|
|
||||||
(defvar-local focus-post-overlay nil
|
|
||||||
"The overlay that dims the text past the current-point.")
|
|
||||||
|
|
||||||
(defvar-local focus-read-only-blink-timer nil
|
|
||||||
"Timer started from `focus-read-only-cursor-blink'.
|
|
||||||
The timer calls `focus-read-only-hide-cursor' after
|
|
||||||
`focus-read-only-blink-seconds' seconds.")
|
|
||||||
|
|
||||||
(defvar-local focus-update-timer nil
|
|
||||||
"Timer started from `focus-update'")
|
|
||||||
|
|
||||||
(defun focus-get-thing ()
|
|
||||||
"Return the current thing, based on `focus-mode-to-thing'.
|
|
||||||
|
|
||||||
This also sets `focus-current-thing-cache' to the current thing."
|
|
||||||
(or focus-current-thing
|
|
||||||
focus-current-thing-cache
|
|
||||||
(setq focus-current-thing-cache
|
|
||||||
(let* ((modes (mapcar 'car focus-mode-to-thing))
|
|
||||||
(mode (or (cl-find major-mode modes)
|
|
||||||
(apply #'derived-mode-p modes))))
|
|
||||||
(if mode (cdr (assoc mode focus-mode-to-thing)) 'sentence)))))
|
|
||||||
|
|
||||||
(defun focus-bounds ()
|
|
||||||
"Return the current bounds, based on `focus-get-thing'."
|
|
||||||
(let ((thing (focus-get-thing)))
|
|
||||||
(cond ((eq thing 'org-element)
|
|
||||||
(let* ((elem (org-element-at-point))
|
|
||||||
(beg (org-element-property :begin elem))
|
|
||||||
(end (org-element-property :end elem)))
|
|
||||||
(cons beg end)))
|
|
||||||
(t (bounds-of-thing-at-point thing)))))
|
|
||||||
|
|
||||||
(defun focus-move-focus (buffer)
|
|
||||||
"Move the focused section according to `focus-bounds'.
|
|
||||||
|
|
||||||
If `focus-mode' is enabled, this command fires after each
|
|
||||||
command."
|
|
||||||
(with-current-buffer buffer
|
|
||||||
(setq focus-update-timer nil)
|
|
||||||
(let* ((bounds (focus-bounds)))
|
|
||||||
(when bounds
|
|
||||||
(focus-move-overlays (car bounds) (cdr bounds))))))
|
|
||||||
|
|
||||||
(defun focus-update ()
|
|
||||||
"Trigger an update of the focus.
|
|
||||||
|
|
||||||
When `focus-update-idle-delay' is non-nil, start update after the
|
|
||||||
specified idle delay."
|
|
||||||
(if focus-update-idle-delay
|
|
||||||
(unless focus-update-timer
|
|
||||||
(setq focus-update-timer
|
|
||||||
(run-with-idle-timer focus-update-idle-delay nil
|
|
||||||
#'focus-move-focus focus-buffer)))
|
|
||||||
(focus-move-focus focus-buffer)))
|
|
||||||
|
|
||||||
(defun focus-move-overlays (low high)
|
|
||||||
"Move the overlays to highlight the region between LOW and HIGH."
|
|
||||||
(move-overlay focus-pre-overlay (point-min) low)
|
|
||||||
(move-overlay focus-mid-overlay low high)
|
|
||||||
(move-overlay focus-post-overlay high (point-max)))
|
|
||||||
|
|
||||||
(defun focus-init ()
|
|
||||||
"This function is run when command `focus-mode' is enabled.
|
|
||||||
|
|
||||||
It sets the `focus-pre-overlay', `focus-min-overlay', and
|
|
||||||
`focus-post-overlay' to overlays; these are invisible until
|
|
||||||
`focus-update' is run. It adds `focus-update' to
|
|
||||||
`post-command-hook'."
|
|
||||||
(unless (or focus-pre-overlay focus-post-overlay)
|
|
||||||
(setq focus-pre-overlay (make-overlay (point-min) (point-min))
|
|
||||||
focus-mid-overlay (make-overlay (point-min) (point-max))
|
|
||||||
focus-post-overlay (make-overlay (point-max) (point-max))
|
|
||||||
focus-buffer (current-buffer))
|
|
||||||
(overlay-put focus-mid-overlay 'face 'focus-focused)
|
|
||||||
(mapc (lambda (o) (overlay-put o 'face 'focus-unfocused))
|
|
||||||
(list focus-pre-overlay focus-post-overlay))
|
|
||||||
(setq focus-current-thing-cache nil
|
|
||||||
focus-update-timer nil)
|
|
||||||
(add-hook 'post-command-hook 'focus-update nil t)
|
|
||||||
(add-hook 'change-major-mode-hook 'focus-terminate nil t)))
|
|
||||||
|
|
||||||
(defun focus-terminate ()
|
|
||||||
"This function is run when command `focus-mode' is disabled.
|
|
||||||
|
|
||||||
The overlays pointed to by `focus-pre-overlay',
|
|
||||||
`focus-mid-overlay' and `focus-post-overlay' are deleted, and
|
|
||||||
`focus-update' is removed from `post-command-hook'."
|
|
||||||
(when (and focus-pre-overlay focus-post-overlay)
|
|
||||||
(mapc 'delete-overlay
|
|
||||||
(list focus-pre-overlay focus-mid-overlay focus-post-overlay))
|
|
||||||
(remove-hook 'post-command-hook 'focus-update t)
|
|
||||||
(when focus-update-timer
|
|
||||||
(cancel-timer focus-update-timer))
|
|
||||||
(setq focus-current-thing-cache nil
|
|
||||||
focus-update-timer nil
|
|
||||||
focus-pre-overlay nil
|
|
||||||
focus-mid-overlay nil
|
|
||||||
focus-post-overlay nil)))
|
|
||||||
|
|
||||||
(defun focus-goto-thing (bounds)
|
|
||||||
"Move point to the middle of BOUNDS."
|
|
||||||
(when bounds
|
|
||||||
(goto-char (/ (+ (car bounds) (cdr bounds)) 2))
|
|
||||||
(recenter nil)))
|
|
||||||
|
|
||||||
(defun focus-change-thing ()
|
|
||||||
"Adjust the narrowness of the focused section for the current buffer.
|
|
||||||
|
|
||||||
The variable `focus-mode-to-thing' dictates the default thing
|
|
||||||
according to major-mode. If `focus-current-thing' is set, this
|
|
||||||
default is overwritten. This function simply helps set the
|
|
||||||
`focus-current-thing'."
|
|
||||||
(interactive)
|
|
||||||
(let* ((candidates '(defun line list org-element paragraph sentence sexp symbol word))
|
|
||||||
(thing (completing-read "Thing: " candidates)))
|
|
||||||
(setq focus-current-thing (intern thing))))
|
|
||||||
|
|
||||||
(defun focus-pin ()
|
|
||||||
"Pin the focused section to its current location or the region, if active."
|
|
||||||
(interactive)
|
|
||||||
(when (bound-and-true-p focus-mode)
|
|
||||||
(when (region-active-p)
|
|
||||||
(focus-move-overlays (region-beginning) (region-end)))
|
|
||||||
(when focus-update-timer
|
|
||||||
(cancel-timer focus-update-timer))
|
|
||||||
(setq focus-update-timer nil)
|
|
||||||
(remove-hook 'post-command-hook 'focus-update t)))
|
|
||||||
|
|
||||||
(defun focus-unpin ()
|
|
||||||
"Unpin the focused section."
|
|
||||||
(interactive)
|
|
||||||
(when (bound-and-true-p focus-mode)
|
|
||||||
(add-hook 'post-command-hook 'focus-update nil t)))
|
|
||||||
|
|
||||||
(defun focus-next-thing (&optional n)
|
|
||||||
"Move the point to the middle of the Nth next thing."
|
|
||||||
(interactive "p")
|
|
||||||
(let ((current-bounds (focus-bounds))
|
|
||||||
(thing (focus-get-thing)))
|
|
||||||
(forward-thing thing n)
|
|
||||||
(when (equal current-bounds (focus-bounds))
|
|
||||||
(forward-thing thing (cl-signum n)))
|
|
||||||
(focus-goto-thing (focus-bounds))))
|
|
||||||
|
|
||||||
(defun focus-prev-thing (&optional n)
|
|
||||||
"Move the point to the middle of the Nth previous thing."
|
|
||||||
(interactive "p")
|
|
||||||
(focus-next-thing (- n)))
|
|
||||||
|
|
||||||
(defun focus-read-only-hide-cursor ()
|
|
||||||
"Hide the cursor.
|
|
||||||
This function is triggered by the `focus-read-only-blink-timer',
|
|
||||||
when `focus-read-only-mode' is activated."
|
|
||||||
(with-current-buffer focus-buffer
|
|
||||||
(when (and (bound-and-true-p focus-read-only-mode)
|
|
||||||
(not (null focus-read-only-blink-timer)))
|
|
||||||
(setq focus-read-only-blink-timer nil)
|
|
||||||
(setq cursor-type nil))))
|
|
||||||
|
|
||||||
(defun focus-read-only-cursor-blink ()
|
|
||||||
"Make the cursor visible for `focus-read-only-blink-seconds'.
|
|
||||||
This is added to the `pre-command-hook' when
|
|
||||||
`focus-read-only-mode' is active."
|
|
||||||
(with-current-buffer focus-buffer
|
|
||||||
(when (and (bound-and-true-p focus-read-only-mode)
|
|
||||||
(not (member last-command '(focus-next-thing focus-prev-thing))))
|
|
||||||
(when focus-read-only-blink-timer (cancel-timer focus-read-only-blink-timer))
|
|
||||||
(setq cursor-type focus-cursor-type)
|
|
||||||
(setq focus-read-only-blink-timer
|
|
||||||
(run-at-time focus-read-only-blink-seconds nil
|
|
||||||
'focus-read-only-hide-cursor)))))
|
|
||||||
|
|
||||||
(defun focus-read-only-init ()
|
|
||||||
"Run when `focus-read-only-mode' is activated.
|
|
||||||
Enables `read-only-mode', hides the cursor and adds
|
|
||||||
`focus-read-only-cursor-blink' to `pre-command-hook'.
|
|
||||||
Also `focus-read-only-terminate' is added to the `kill-buffer-hook'."
|
|
||||||
(read-only-mode 1)
|
|
||||||
(setq cursor-type nil
|
|
||||||
focus-buffer (current-buffer))
|
|
||||||
(add-hook 'pre-command-hook 'focus-read-only-cursor-blink nil t)
|
|
||||||
(add-hook 'kill-buffer-hook 'focus-read-only-terminate nil t))
|
|
||||||
|
|
||||||
(defun focus-read-only-terminate ()
|
|
||||||
"Run when `focus-read-only-mode' is deactivated.
|
|
||||||
Disables `read-only-mode' and shows the cursor again.
|
|
||||||
It cleans up the `focus-read-only-blink-timer' and hooks."
|
|
||||||
(read-only-mode -1)
|
|
||||||
(setq cursor-type focus-cursor-type)
|
|
||||||
(when focus-read-only-blink-timer
|
|
||||||
(cancel-timer focus-read-only-blink-timer))
|
|
||||||
(setq focus-read-only-blink-timer nil)
|
|
||||||
(remove-hook 'pre-command-hook 'focus-read-only-cursor-blink t)
|
|
||||||
(remove-hook 'kill-buffer-hook 'focus-read-only-terminate t))
|
|
||||||
|
|
||||||
(defun focus-turn-off-focus-read-only-mode ()
|
|
||||||
"Turn off `focus-read-only-mode'."
|
|
||||||
(interactive)
|
|
||||||
(focus-read-only-mode -1))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(define-minor-mode focus-mode
|
|
||||||
"Dim the font color of text in surrounding sections."
|
|
||||||
:init-value nil
|
|
||||||
:keymap (let ((map (make-sparse-keymap)))
|
|
||||||
(define-key map (kbd "C-c C-q") 'focus-read-only-mode)
|
|
||||||
map)
|
|
||||||
(if focus-mode (focus-init) (focus-terminate)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(define-minor-mode focus-read-only-mode
|
|
||||||
"A read-only mode optimized for `focus-mode'."
|
|
||||||
:init-value nil
|
|
||||||
:keymap (let ((map (make-sparse-keymap)))
|
|
||||||
(define-key map (kbd "n") 'focus-next-thing)
|
|
||||||
(define-key map (kbd "SPC") 'focus-next-thing)
|
|
||||||
(define-key map (kbd "p") 'focus-prev-thing)
|
|
||||||
(define-key map (kbd "S-SPC") 'focus-prev-thing)
|
|
||||||
(define-key map (kbd "i") 'focus-turn-off-focus-read-only-mode)
|
|
||||||
(define-key map (kbd "q") 'focus-turn-off-focus-read-only-mode)
|
|
||||||
map)
|
|
||||||
(when cursor-type
|
|
||||||
(setq focus-cursor-type cursor-type))
|
|
||||||
(if focus-read-only-mode (focus-read-only-init) (focus-read-only-terminate)))
|
|
||||||
|
|
||||||
(provide 'focus)
|
|
||||||
;;; focus.el ends here
|
|
|
@ -1,115 +0,0 @@
|
||||||
;;; go-mode-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
|
|
||||||
;; Generated by the `loaddefs-generate' function.
|
|
||||||
|
|
||||||
;; This file is part of GNU Emacs.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; Generated autoloads from go-mode.el
|
|
||||||
|
|
||||||
(autoload 'go-mode "go-mode" "\
|
|
||||||
Major mode for editing Go source text.
|
|
||||||
|
|
||||||
This mode provides (not just) basic editing capabilities for
|
|
||||||
working with Go code. It offers almost complete syntax
|
|
||||||
highlighting, indentation that is almost identical to gofmt and
|
|
||||||
proper parsing of the buffer content to allow features such as
|
|
||||||
navigation by function, manipulation of comments or detection of
|
|
||||||
strings.
|
|
||||||
|
|
||||||
In addition to these core features, it offers various features to
|
|
||||||
help with writing Go code. You can directly run buffer content
|
|
||||||
through gofmt, read godoc documentation from within Emacs, modify
|
|
||||||
and clean up the list of package imports or interact with the
|
|
||||||
Playground (uploading and downloading pastes).
|
|
||||||
|
|
||||||
The following extra functions are defined:
|
|
||||||
|
|
||||||
- `gofmt'
|
|
||||||
- `godoc' and `godoc-at-point'
|
|
||||||
- `go-import-add'
|
|
||||||
- `go-goto-arguments'
|
|
||||||
- `go-goto-docstring'
|
|
||||||
- `go-goto-function'
|
|
||||||
- `go-goto-function-name'
|
|
||||||
- `go-goto-imports'
|
|
||||||
- `go-goto-return-values'
|
|
||||||
- `go-goto-method-receiver'
|
|
||||||
- `go-play-buffer' and `go-play-region'
|
|
||||||
- `go-download-play'
|
|
||||||
- `godef-describe' and `godef-jump'
|
|
||||||
- `go-coverage'
|
|
||||||
|
|
||||||
If you want to automatically run `gofmt' before saving a file,
|
|
||||||
add the following hook to your Emacs configuration:
|
|
||||||
|
|
||||||
(add-hook 'before-save-hook #'gofmt-before-save)
|
|
||||||
|
|
||||||
If you want to use `godef-jump' instead of etags (or similar),
|
|
||||||
consider binding godef-jump to `M-.', which is the default key
|
|
||||||
for `find-tag':
|
|
||||||
|
|
||||||
(add-hook 'go-mode-hook (lambda ()
|
|
||||||
(local-set-key (kbd \"M-.\") #'godef-jump)))
|
|
||||||
|
|
||||||
Please note that godef is an external dependency. You can install
|
|
||||||
it with
|
|
||||||
|
|
||||||
go get github.com/rogpeppe/godef
|
|
||||||
|
|
||||||
|
|
||||||
If you're looking for even more integration with Go, namely
|
|
||||||
on-the-fly syntax checking, auto-completion and snippets, it is
|
|
||||||
recommended that you look at flycheck
|
|
||||||
(see URL `https://github.com/flycheck/flycheck') or flymake in combination
|
|
||||||
with goflymake (see URL `https://github.com/dougm/goflymake'), gocode
|
|
||||||
(see URL `https://github.com/nsf/gocode'), go-eldoc
|
|
||||||
(see URL `github.com/syohex/emacs-go-eldoc') and yasnippet-go
|
|
||||||
(see URL `https://github.com/dominikh/yasnippet-go')
|
|
||||||
|
|
||||||
(fn)" t)
|
|
||||||
(add-to-list 'auto-mode-alist (cons "\\.go\\'" 'go-mode))
|
|
||||||
(autoload 'gofmt-before-save "go-mode" "\
|
|
||||||
Add this to .emacs to run gofmt on the current buffer when saving:
|
|
||||||
(add-hook 'before-save-hook 'gofmt-before-save).
|
|
||||||
|
|
||||||
Note that this will cause ‘go-mode’ to get loaded the first time
|
|
||||||
you save any file, kind of defeating the point of autoloading." t)
|
|
||||||
(autoload 'godoc "go-mode" "\
|
|
||||||
Show Go documentation for QUERY, much like \\<go-mode-map>\\[man].
|
|
||||||
|
|
||||||
(fn QUERY)" t)
|
|
||||||
(autoload 'go-download-play "go-mode" "\
|
|
||||||
Download a paste from the playground and insert it in a Go buffer.
|
|
||||||
Tries to look for a URL at point.
|
|
||||||
|
|
||||||
(fn URL)" t)
|
|
||||||
(autoload 'go-dot-mod-mode "go-mode" "\
|
|
||||||
A major mode for editing go.mod files.
|
|
||||||
|
|
||||||
(fn)" t)
|
|
||||||
(add-to-list 'auto-mode-alist '("go\\.mod\\'" . go-dot-mod-mode))
|
|
||||||
(autoload 'go-dot-work-mode "go-mode" "\
|
|
||||||
A major mode for editor go.work files.
|
|
||||||
|
|
||||||
(fn)" t)
|
|
||||||
(add-to-list 'auto-mode-alist '("go\\.work\\'" . go-dot-work-mode))
|
|
||||||
(register-definition-prefixes "go-mode" '("go-" "god" "gofmt"))
|
|
||||||
|
|
||||||
;;; End of scraped data
|
|
||||||
|
|
||||||
(provide 'go-mode-autoloads)
|
|
||||||
|
|
||||||
;; Local Variables:
|
|
||||||
;; version-control: never
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; no-update-autoloads: t
|
|
||||||
;; no-native-compile: t
|
|
||||||
;; coding: utf-8-emacs-unix
|
|
||||||
;; End:
|
|
||||||
|
|
||||||
;;; go-mode-autoloads.el ends here
|
|
|
@ -1,8 +0,0 @@
|
||||||
(define-package "go-mode" "20240620.1948" "Major mode for the Go programming language"
|
|
||||||
'((emacs "26.1"))
|
|
||||||
:commit "636d36e37a0d2b6adb2e12d802ff4794ccbba336" :keywords
|
|
||||||
'("languages" "go")
|
|
||||||
:url "https://github.com/dominikh/go-mode.el")
|
|
||||||
;; Local Variables:
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; End:
|
|
File diff suppressed because it is too large
Load diff
|
@ -156,37 +156,27 @@ fi
|
||||||
|
|
||||||
|
|
||||||
cat > $CONF_FILE <<EOF
|
cat > $CONF_FILE <<EOF
|
||||||
(setq initial-scratch-message
|
(setq initial-scratch-message (concat initial-scratch-message
|
||||||
";; This buffer is for text that is not saved, and for Lisp evaluation.\\n\
|
";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\\n\
|
||||||
;; You can hit \`C-j' at end of a lisp expression to eval it.\\n\\n\
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\\n\
|
|
||||||
;; This Emacs is Powered by \`HELM' using\\n\
|
;; This Emacs is Powered by \`HELM' using\\n\
|
||||||
;; emacs program \"$EMACS\".\\n\
|
;; emacs program \"$EMACS\".\\n\
|
||||||
;; This is a minimal \`helm' configuration to discover \`helm' or debug it.\\n\
|
;; This is a minimal \`helm' configuration to discover \`helm' or debug it.\\n\
|
||||||
;; You can retrieve this minimal configuration in \"$CONF_FILE\".\\n\
|
;; You can retrieve this minimal configuration in \"$CONF_FILE\".\\n\
|
||||||
|
;;
|
||||||
;; Some original Emacs commands are replaced by their \`helm' counterparts:\\n\\n\
|
;; Some original Emacs commands are replaced by their \`helm' counterparts:\\n\\n\
|
||||||
;; - \`find-file'(C-x C-f) =>\`helm-find-files'\\n\
|
;; - \`find-file'(C-x C-f) =>\`helm-find-files'\\n\
|
||||||
;; - \`occur'(M-s o) =>\`helm-occur'\\n\
|
;; - \`occur'(M-s o) =>\`helm-occur'\\n\
|
||||||
;; - \`list-buffers'(C-x C-b) =>\`helm-buffers-list'\\n\
|
;; - \`list-buffers'(C-x C-b) =>\`helm-buffers-list'\\n\
|
||||||
|
;; - \`completion-at-point'(M-tab) =>\`helm-lisp-completion-at-point'[1]\\n\
|
||||||
;; - \`apropos-command'(C-h a) =>\`helm-apropos'\\n\
|
;; - \`apropos-command'(C-h a) =>\`helm-apropos'\\n\
|
||||||
;; - \`dabbrev-expand'(M-/) =>\`helm-dabbrev'\\n\
|
;; - \`dabbrev-expand'(M-/) =>\`helm-dabbrev'\\n\
|
||||||
;; - \`execute-extended-command'(M-x) =>\`helm-M-x'\\n\\n
|
;; - \`execute-extended-command'(M-x) =>\`helm-M-x'\\n\\n
|
||||||
;; \`helm-mode' is enabled which mean that most Emacs commands using completion\\n\
|
;; Some other Emacs commands are \"helmized\" by \`helm-mode'.\\n\
|
||||||
;; will use helm.\\n\
|
;; [1] Coming with emacs-24.4, \`completion-at-point' is \"helmized\" by \`helm-mode'\\n\
|
||||||
|
|
||||||
;; To start editing a file or to create a new file, visit it with \`C-x C-f'\\n\
|
;; which provides Helm completion in many places like \`shell-mode'.\\n\
|
||||||
;; and enter text in its buffer, to save your changes hit \`C-x C-s'.
|
;; Find context help for most Helm commands with \`C-h m'.\\n\
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\\n\\n"))
|
||||||
;; Find context help for most Helm commands with \`C-h m' while helm is running.\\n\
|
|
||||||
;; You can also retrieve the whole user documentation with \`C-x c h h'.\\n\
|
|
||||||
;; For online documentation see \`https://github.com/emacs-helm/helm/wiki'.\\n\
|
|
||||||
;; \(Put cursor on url, hit \`C-x C-f' and then RETurn).\\n\
|
|
||||||
|
|
||||||
;; To quit this Emacs, hit \'C-x C-c'.\\n\
|
|
||||||
|
|
||||||
;; Note about keybindings in Emacs: \`C-' means \'Control-' and \`M-' \'Alt-'.\\n\
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\\n\\n")
|
|
||||||
|
|
||||||
(setq load-path (quote $LOAD_PATH))
|
(setq load-path (quote $LOAD_PATH))
|
||||||
|
|
||||||
|
@ -243,7 +233,7 @@ cat > $CONF_FILE <<EOF
|
||||||
(setq package-load-list
|
(setq package-load-list
|
||||||
(if (equal load-packages '("all"))
|
(if (equal load-packages '("all"))
|
||||||
'(all)
|
'(all)
|
||||||
(append '((helm-core t) (helm t) (async t) (wfnames t))
|
(append '((helm-core t) (helm t) (async t) (popup t))
|
||||||
(mapcar (lambda (p) (list (intern p) t)) load-packages)))))
|
(mapcar (lambda (p) (list (intern p) t)) load-packages)))))
|
||||||
|
|
||||||
(package-initialize))
|
(package-initialize))
|
||||||
|
@ -266,6 +256,9 @@ cat > $CONF_FILE <<EOF
|
||||||
(define-key global-map [remap dabbrev-expand] 'helm-dabbrev)
|
(define-key global-map [remap dabbrev-expand] 'helm-dabbrev)
|
||||||
(define-key global-map [remap execute-extended-command] 'helm-M-x)
|
(define-key global-map [remap execute-extended-command] 'helm-M-x)
|
||||||
(define-key global-map [remap apropos-command] 'helm-apropos)
|
(define-key global-map [remap apropos-command] 'helm-apropos)
|
||||||
|
(unless (boundp 'completion-in-region-function)
|
||||||
|
(define-key lisp-interaction-mode-map [remap completion-at-point] 'helm-lisp-completion-at-point)
|
||||||
|
(define-key emacs-lisp-mode-map [remap completion-at-point] 'helm-lisp-completion-at-point))
|
||||||
(add-hook 'kill-emacs-hook #'(lambda () (and (file-exists-p "$CONF_FILE") (delete-file "$CONF_FILE"))))
|
(add-hook 'kill-emacs-hook #'(lambda () (and (file-exists-p "$CONF_FILE") (delete-file "$CONF_FILE"))))
|
||||||
EOF
|
EOF
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -33,7 +33,6 @@
|
||||||
(declare-function all-the-icons-icon-for-file"ext:all-the-icons.el")
|
(declare-function all-the-icons-icon-for-file"ext:all-the-icons.el")
|
||||||
(declare-function all-the-icons-octicon "ext:all-the-icons.el")
|
(declare-function all-the-icons-octicon "ext:all-the-icons.el")
|
||||||
(declare-function all-the-icons-match-to-alist "ext:all-the-icons.el")
|
(declare-function all-the-icons-match-to-alist "ext:all-the-icons.el")
|
||||||
(declare-function all-the-icons-faicon "ext:all-the-icons.el")
|
|
||||||
|
|
||||||
(defvar all-the-icons-dir-icon-alist)
|
(defvar all-the-icons-dir-icon-alist)
|
||||||
|
|
||||||
|
@ -66,7 +65,7 @@
|
||||||
Don't use `setq' to set this."
|
Don't use `setq' to set this."
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:set (lambda (var val)
|
:set (lambda (var val)
|
||||||
(if (require 'all-the-icons nil t)
|
(if (featurep 'all-the-icons)
|
||||||
(set var val)
|
(set var val)
|
||||||
(set var nil))))
|
(set var nil))))
|
||||||
|
|
||||||
|
@ -89,10 +88,6 @@ will be honored."
|
||||||
helm-bookmark-default-filtered-sources)
|
helm-bookmark-default-filtered-sources)
|
||||||
for fn = (intern (format "%s-builder" s))
|
for fn = (intern (format "%s-builder" s))
|
||||||
do (set s (funcall fn)))))
|
do (set s (funcall fn)))))
|
||||||
|
|
||||||
(defcustom helm-bookmark-annotation-sign "*"
|
|
||||||
"Boomarks with annotation are prefixed with this string."
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defgroup helm-bookmark-faces nil
|
(defgroup helm-bookmark-faces nil
|
||||||
"Customize the appearance of helm-bookmark."
|
"Customize the appearance of helm-bookmark."
|
||||||
|
@ -255,8 +250,7 @@ will be honored."
|
||||||
BOOKMARK is a bookmark name or a bookmark record."
|
BOOKMARK is a bookmark name or a bookmark record."
|
||||||
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-gnus)
|
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-gnus)
|
||||||
(eq (bookmark-get-handler bookmark) 'gnus-summary-bookmark-jump)
|
(eq (bookmark-get-handler bookmark) 'gnus-summary-bookmark-jump)
|
||||||
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-gnus)
|
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-gnus)))
|
||||||
(eq (bookmark-get-handler bookmark) 'bmkp-jump-gnus)))
|
|
||||||
|
|
||||||
(defun helm-bookmark-mu4e-bookmark-p (bookmark)
|
(defun helm-bookmark-mu4e-bookmark-p (bookmark)
|
||||||
"Return non nil if BOOKMARK is a mu4e bookmark.
|
"Return non nil if BOOKMARK is a mu4e bookmark.
|
||||||
|
@ -269,24 +263,21 @@ BOOKMARK is a bookmark name or a bookmark record."
|
||||||
BOOKMARK is a bookmark name or a bookmark record."
|
BOOKMARK is a bookmark name or a bookmark record."
|
||||||
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-w3m)
|
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-w3m)
|
||||||
(eq (bookmark-get-handler bookmark) 'bookmark-w3m-bookmark-jump)
|
(eq (bookmark-get-handler bookmark) 'bookmark-w3m-bookmark-jump)
|
||||||
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-w3m)
|
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-w3m)))
|
||||||
(eq (bookmark-get-handler bookmark) 'bmkp-jump-w3m)))
|
|
||||||
|
|
||||||
(defun helm-bookmark-woman-bookmark-p (bookmark)
|
(defun helm-bookmark-woman-bookmark-p (bookmark)
|
||||||
"Return non-nil if BOOKMARK is a Woman bookmark.
|
"Return non-nil if BOOKMARK is a Woman bookmark.
|
||||||
BOOKMARK is a bookmark name or a bookmark record."
|
BOOKMARK is a bookmark name or a bookmark record."
|
||||||
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-woman)
|
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-woman)
|
||||||
(eq (bookmark-get-handler bookmark) 'woman-bookmark-jump)
|
(eq (bookmark-get-handler bookmark) 'woman-bookmark-jump)
|
||||||
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-woman)
|
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-woman)))
|
||||||
(eq (bookmark-get-handler bookmark) 'bmkp-jump-woman)))
|
|
||||||
|
|
||||||
(defun helm-bookmark-man-bookmark-p (bookmark)
|
(defun helm-bookmark-man-bookmark-p (bookmark)
|
||||||
"Return non-nil if BOOKMARK is a Man bookmark.
|
"Return non-nil if BOOKMARK is a Man bookmark.
|
||||||
BOOKMARK is a bookmark name or a bookmark record."
|
BOOKMARK is a bookmark name or a bookmark record."
|
||||||
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-man)
|
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-man)
|
||||||
(eq (bookmark-get-handler bookmark) 'Man-bookmark-jump)
|
(eq (bookmark-get-handler bookmark) 'Man-bookmark-jump)
|
||||||
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-man)
|
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-man)))
|
||||||
(eq (bookmark-get-handler bookmark) 'bmkp-jump-man)))
|
|
||||||
|
|
||||||
(defun helm-bookmark-woman-man-bookmark-p (bookmark)
|
(defun helm-bookmark-woman-man-bookmark-p (bookmark)
|
||||||
"Return non-nil if BOOKMARK is a Man or Woman bookmark.
|
"Return non-nil if BOOKMARK is a Man or Woman bookmark.
|
||||||
|
@ -311,10 +302,7 @@ BOOKMARK is a bookmark name or a bookmark record.
|
||||||
This excludes bookmarks of a more specific kind (Info, Gnus, and W3m)."
|
This excludes bookmarks of a more specific kind (Info, Gnus, and W3m)."
|
||||||
(let* ((filename (bookmark-get-filename bookmark))
|
(let* ((filename (bookmark-get-filename bookmark))
|
||||||
(isnonfile (equal filename helm-bookmark--non-file-filename)))
|
(isnonfile (equal filename helm-bookmark--non-file-filename)))
|
||||||
(and filename
|
(and filename (not isnonfile) (not (bookmark-get-handler bookmark)))))
|
||||||
(not isnonfile)
|
|
||||||
(not (helm-bookmark-org-file-p bookmark))
|
|
||||||
(not (bookmark-get-handler bookmark)))))
|
|
||||||
|
|
||||||
(defun helm-bookmark-org-file-p (bookmark)
|
(defun helm-bookmark-org-file-p (bookmark)
|
||||||
(let* ((filename (bookmark-get-filename bookmark)))
|
(let* ((filename (bookmark-get-filename bookmark)))
|
||||||
|
@ -400,10 +388,6 @@ If `browse-url-browser-function' is set to something else than
|
||||||
(defalias 'bookmarkp-jump-w3m #'helm-bookmark-jump-w3m)
|
(defalias 'bookmarkp-jump-w3m #'helm-bookmark-jump-w3m)
|
||||||
(defalias 'bookmarkp-jump-woman #'woman-bookmark-jump)
|
(defalias 'bookmarkp-jump-woman #'woman-bookmark-jump)
|
||||||
(defalias 'bookmarkp-jump-man #'Man-bookmark-jump)
|
(defalias 'bookmarkp-jump-man #'Man-bookmark-jump)
|
||||||
(defalias 'bmkp-jump-gnus #'gnus-summary-bookmark-jump)
|
|
||||||
(defalias 'bmkp-jump-w3m #'helm-bookmark-jump-w3m)
|
|
||||||
(defalias 'bmkp-jump-woman #'woman-bookmark-jump)
|
|
||||||
(defalias 'bmkp-jump-man #'Man-bookmark-jump)
|
|
||||||
|
|
||||||
|
|
||||||
;;;; Filtered bookmark sources
|
;;;; Filtered bookmark sources
|
||||||
|
@ -635,17 +619,15 @@ If `browse-url-browser-function' is set to something else than
|
||||||
all-the-icons-dir-icon-alist))
|
all-the-icons-dir-icon-alist))
|
||||||
(apply (car it) (cdr it))
|
(apply (car it) (cdr it))
|
||||||
(all-the-icons-octicon "file-directory")))
|
(all-the-icons-octicon "file-directory")))
|
||||||
(isw3m (all-the-icons-faicon "firefox"))
|
|
||||||
((and isfile isinfo) (all-the-icons-octicon "info"))
|
((and isfile isinfo) (all-the-icons-octicon "info"))
|
||||||
|
(isfile (all-the-icons-icon-for-file isfile))
|
||||||
((or iswoman isman)
|
((or iswoman isman)
|
||||||
(all-the-icons-fileicon "man-page"))
|
(all-the-icons-fileicon "man-page"))
|
||||||
((or isgnus ismu4e)
|
((or isgnus ismu4e)
|
||||||
(all-the-icons-octicon "mail-read"))
|
(all-the-icons-octicon "mail-read"))))
|
||||||
(isfile (all-the-icons-icon-for-file (helm-basename isfile)))))
|
|
||||||
;; Add a * if bookmark have annotation
|
;; Add a * if bookmark have annotation
|
||||||
if (and isannotation (not (string-equal isannotation "")))
|
if (and isannotation (not (string-equal isannotation "")))
|
||||||
do (setq trunc (concat helm-bookmark-annotation-sign
|
do (setq trunc (concat "*" (if helm-bookmark-show-location trunc i)))
|
||||||
(if helm-bookmark-show-location trunc i)))
|
|
||||||
for sep = (and helm-bookmark-show-location
|
for sep = (and helm-bookmark-show-location
|
||||||
(make-string (- (+ bookmark-bmenu-file-column 2)
|
(make-string (- (+ bookmark-bmenu-file-column 2)
|
||||||
(string-width trunc))
|
(string-width trunc))
|
||||||
|
@ -767,43 +749,32 @@ renamed."
|
||||||
(setq bookmark-alist-modification-count (1+ bookmark-alist-modification-count))
|
(setq bookmark-alist-modification-count (1+ bookmark-alist-modification-count))
|
||||||
(when (bookmark-time-to-save-p) (bookmark-save)))
|
(when (bookmark-time-to-save-p) (bookmark-save)))
|
||||||
|
|
||||||
(defun helm-bookmark-rename (old &optional new _batch)
|
(defun helm-bookmark-rename (old &optional new batch)
|
||||||
"Change bookmark's name from OLD to NEW.
|
"Change bookmark's name from OLD to NEW.
|
||||||
|
Interactively:
|
||||||
|
If called from the keyboard, then prompt for OLD.
|
||||||
|
If called from the menubar, select OLD from a menu.
|
||||||
If NEW is nil, then prompt for its string value.
|
If NEW is nil, then prompt for its string value.
|
||||||
|
|
||||||
Unused arg _BATCH is kept for backward compatibility.
|
If BATCH is non-nil, then do not rebuild the menu list.
|
||||||
|
|
||||||
While the user enters the new name, repeated `C-w' inserts
|
While the user enters the new name, repeated `C-w' inserts
|
||||||
consecutive words from the buffer into the new bookmark name."
|
consecutive words from the buffer into the new bookmark name."
|
||||||
|
(interactive (list (bookmark-completing-read "Old bookmark name")))
|
||||||
(bookmark-maybe-historicize-string old)
|
(bookmark-maybe-historicize-string old)
|
||||||
(bookmark-maybe-load-default-file)
|
(bookmark-maybe-load-default-file)
|
||||||
(save-excursion
|
(save-excursion (skip-chars-forward " ") (setq bookmark-yank-point (point)))
|
||||||
(skip-chars-forward " ") (setq bookmark-yank-point (point)))
|
|
||||||
(setq bookmark-current-buffer (current-buffer))
|
(setq bookmark-current-buffer (current-buffer))
|
||||||
(catch 'skip
|
(let ((newname (or new (read-from-minibuffer
|
||||||
(let ((newname
|
"New name: " nil
|
||||||
(or new (read-from-minibuffer
|
(let ((now-map (copy-keymap minibuffer-local-map)))
|
||||||
;; `format-prompt' is not available in old Emacs.
|
(define-key now-map "\C-w" #'bookmark-yank-word)
|
||||||
(format "New name [C-RET to skip] (default %s): " old) nil
|
now-map)
|
||||||
(let ((now-map (copy-keymap minibuffer-local-map)))
|
nil 'bookmark-history))))
|
||||||
(define-key now-map "\C-w" #'bookmark-yank-word)
|
(bookmark-set-name old newname)
|
||||||
(define-key now-map (kbd "C-<return>")
|
(setq bookmark-current-bookmark newname)
|
||||||
#'(lambda () (interactive) (throw 'skip 'skip)))
|
(unless batch (bookmark-bmenu-surreptitiously-rebuild-list))
|
||||||
now-map)
|
(helm-bookmark-maybe-save-bookmark) newname))
|
||||||
nil 'bookmark-history old))))
|
|
||||||
(bookmark-set-name old newname)
|
|
||||||
(setq bookmark-current-bookmark newname)
|
|
||||||
(helm-bookmark-maybe-save-bookmark) newname)))
|
|
||||||
|
|
||||||
(defun helm-bookmark-rename-marked (_candidate)
|
|
||||||
"Rename marked bookmarks."
|
|
||||||
(let* ((bmks (helm-marked-candidates))
|
|
||||||
(count 0)
|
|
||||||
(len (length bmks)))
|
|
||||||
(cl-loop for bmk in bmks
|
|
||||||
unless (eq (helm-bookmark-rename bmk) 'skip)
|
|
||||||
do (cl-incf count))
|
|
||||||
(message "(%s/%s) bookmark(s) renamed" count len)))
|
|
||||||
|
|
||||||
(helm-make-command-from-action helm-bookmark-run-edit
|
(helm-make-command-from-action helm-bookmark-run-edit
|
||||||
"Run `helm-bookmark-edit-bookmark' from keyboard."
|
"Run `helm-bookmark-edit-bookmark' from keyboard."
|
||||||
|
@ -837,65 +808,7 @@ E.g. prepended with *."
|
||||||
(dolist (i (helm-marked-candidates))
|
(dolist (i (helm-marked-candidates))
|
||||||
(bookmark-delete (helm-bookmark-get-bookmark-from-name i)
|
(bookmark-delete (helm-bookmark-get-bookmark-from-name i)
|
||||||
'batch)))
|
'batch)))
|
||||||
|
|
||||||
;;; bookmark annotations
|
|
||||||
;;
|
|
||||||
(defun helm-bookmark-show-annotation (bookmark-name-or-record)
|
|
||||||
"Display the annotation for BOOKMARK-NAME-OR-RECORD in a buffer."
|
|
||||||
(let ((annotation (bookmark-get-annotation bookmark-name-or-record)))
|
|
||||||
(when (and annotation (not (string-equal annotation "")))
|
|
||||||
(let ((buf (get-buffer-create "*Bookmark Annotation*")))
|
|
||||||
(with-current-buffer buf
|
|
||||||
(let ((inhibit-read-only t))
|
|
||||||
(erase-buffer)
|
|
||||||
(insert annotation)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(set-buffer-modified-p nil)
|
|
||||||
(helm-bookmark-annotation-mode)
|
|
||||||
(insert (substitute-command-keys
|
|
||||||
"# Edit this buffer with \\[helm-bookmark-edit-annotation]")
|
|
||||||
(substitute-command-keys
|
|
||||||
"\n# Quit this buffer with \\[helm-bookmark-quit-annotation]\n"))
|
|
||||||
(set (make-local-variable 'bookmark-annotation-name)
|
|
||||||
bookmark-name-or-record)
|
|
||||||
(put 'bookmark-annotation-name 'permanent-local t)))
|
|
||||||
(pop-to-buffer buf)))))
|
|
||||||
|
|
||||||
(defun helm-bookmark-edit-annotation ()
|
|
||||||
"Edit bookmark annotation from the show annotation buffer."
|
|
||||||
(interactive)
|
|
||||||
(setq buffer-read-only nil)
|
|
||||||
(bookmark-edit-annotation-mode)
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(delete-region
|
|
||||||
(point) (save-excursion (forward-line 2) (point)))
|
|
||||||
(insert (funcall bookmark-edit-annotation-text-func
|
|
||||||
bookmark-annotation-name))))
|
|
||||||
(put 'helm-bookmark-edit-annotation 'no-helm-mx t)
|
|
||||||
|
|
||||||
(defun helm-bookmark-quit-annotation ()
|
|
||||||
"Quit bookmark annotation buffer."
|
|
||||||
(interactive)
|
|
||||||
(quit-window t))
|
|
||||||
(put 'helm-bookmark-quit-annotation 'no-helm-mx t)
|
|
||||||
|
|
||||||
(defvar helm-bookmark-annotation-mode-map
|
|
||||||
(let ((map (make-sparse-keymap)))
|
|
||||||
(set-keymap-parent map text-mode-map)
|
|
||||||
(define-key map (kbd "q") #'helm-bookmark-quit-annotation)
|
|
||||||
(define-key map (kbd "e") #'helm-bookmark-edit-annotation)
|
|
||||||
map)
|
|
||||||
"Map used in show annotation bookmark buffer.")
|
|
||||||
|
|
||||||
(define-derived-mode helm-bookmark-annotation-mode
|
|
||||||
text-mode "helm-annotation-mode"
|
|
||||||
"Mode to display bookmark annotations.
|
|
||||||
|
|
||||||
Special commands:
|
|
||||||
\\{helm-bookmark-annotation-mode-map}"
|
|
||||||
:interactive nil
|
|
||||||
(setq-local buffer-read-only t))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun helm-bookmarks ()
|
(defun helm-bookmarks ()
|
||||||
|
@ -905,7 +818,7 @@ Special commands:
|
||||||
helm-source-bookmark-set)
|
helm-source-bookmark-set)
|
||||||
:buffer "*helm bookmarks*"
|
:buffer "*helm bookmarks*"
|
||||||
:default (buffer-name helm-current-buffer)))
|
:default (buffer-name helm-current-buffer)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun helm-filtered-bookmarks ()
|
(defun helm-filtered-bookmarks ()
|
||||||
"Preconfigured `helm' for bookmarks (filtered by category).
|
"Preconfigured `helm' for bookmarks (filtered by category).
|
|
@ -36,7 +36,6 @@
|
||||||
(defvar dired-buffers)
|
(defvar dired-buffers)
|
||||||
(defvar org-directory)
|
(defvar org-directory)
|
||||||
(defvar helm-ff-default-directory)
|
(defvar helm-ff-default-directory)
|
||||||
(defvar major-mode-remap-alist)
|
|
||||||
|
|
||||||
|
|
||||||
(defgroup helm-buffers nil
|
(defgroup helm-buffers nil
|
||||||
|
@ -101,10 +100,7 @@ When adding a source here it is up to you to ensure the library
|
||||||
of this source is accessible and properly loaded."
|
of this source is accessible and properly loaded."
|
||||||
:type '(repeat (choice symbol)))
|
:type '(repeat (choice symbol)))
|
||||||
|
|
||||||
(defcustom helm-buffers-end-truncated-string
|
(defcustom helm-buffers-end-truncated-string "..."
|
||||||
;; `truncate-string-ellipsis', the function is not available in 27.1
|
|
||||||
;; See issue#2673.
|
|
||||||
(if (char-displayable-p ?…) "…" "...")
|
|
||||||
"The string to display at end of truncated buffer names."
|
"The string to display at end of truncated buffer names."
|
||||||
:type 'string)
|
:type 'string)
|
||||||
|
|
||||||
|
@ -152,7 +148,7 @@ you want to keep the recentest order when narrowing candidates."
|
||||||
Don't use `setq' to set this."
|
Don't use `setq' to set this."
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:set (lambda (var val)
|
:set (lambda (var val)
|
||||||
(if (require 'all-the-icons nil t)
|
(if (featurep 'all-the-icons)
|
||||||
(set var val)
|
(set var val)
|
||||||
(set var nil))))
|
(set var nil))))
|
||||||
|
|
||||||
|
@ -339,9 +335,6 @@ Note that this variable is buffer-local.")
|
||||||
when (string-match r candidate)
|
when (string-match r candidate)
|
||||||
return m)))
|
return m)))
|
||||||
(buffer (get-buffer-create candidate)))
|
(buffer (get-buffer-create candidate)))
|
||||||
(helm-aif (and (boundp 'major-mode-remap-alist)
|
|
||||||
(cdr (assq mjm major-mode-remap-alist)))
|
|
||||||
(setq mjm it))
|
|
||||||
(if mjm
|
(if mjm
|
||||||
(with-current-buffer buffer (funcall mjm))
|
(with-current-buffer buffer (funcall mjm))
|
||||||
(set-buffer-major-mode buffer))
|
(set-buffer-major-mode buffer))
|
||||||
|
@ -386,7 +379,7 @@ Note that this variable is buffer-local.")
|
||||||
|
|
||||||
|
|
||||||
(defun helm-buffers-get-visible-buffers ()
|
(defun helm-buffers-get-visible-buffers ()
|
||||||
"Returns buffers visible on visible frames."
|
"Returns buffers visibles on current frame."
|
||||||
(let (result)
|
(let (result)
|
||||||
(walk-windows
|
(walk-windows
|
||||||
(lambda (x)
|
(lambda (x)
|
||||||
|
@ -395,7 +388,6 @@ Note that this variable is buffer-local.")
|
||||||
result))
|
result))
|
||||||
|
|
||||||
(defun helm-buffer-list-1 (&optional visibles)
|
(defun helm-buffer-list-1 (&optional visibles)
|
||||||
"Return list of all buffers except VISIBLES buffers."
|
|
||||||
(cl-loop for b in (buffer-list)
|
(cl-loop for b in (buffer-list)
|
||||||
for bn = (buffer-name b)
|
for bn = (buffer-name b)
|
||||||
unless (member bn visibles)
|
unless (member bn visibles)
|
||||||
|
@ -439,7 +431,7 @@ The list is reordered with `helm-buffer-list-reorder-fn'."
|
||||||
(cond ((eq type 'dired)
|
(cond ((eq type 'dired)
|
||||||
(all-the-icons-octicon "file-directory"))
|
(all-the-icons-octicon "file-directory"))
|
||||||
(buf-fname
|
(buf-fname
|
||||||
(all-the-icons-icon-for-file buf-name))
|
(all-the-icons-icon-for-file buf-fname))
|
||||||
(t (all-the-icons-octicon "star" :v-adjust 0.0))))))
|
(t (all-the-icons-octicon "star" :v-adjust 0.0))))))
|
||||||
(buf-name (propertize buf-name 'face face1
|
(buf-name (propertize buf-name 'face face1
|
||||||
'help-echo help-echo
|
'help-echo help-echo
|
||||||
|
@ -460,7 +452,7 @@ The list is reordered with `helm-buffer-list-reorder-fn'."
|
||||||
(format "(%s %s in `%s')"
|
(format "(%s %s in `%s')"
|
||||||
(process-name proc)
|
(process-name proc)
|
||||||
(process-status proc) dir)
|
(process-status proc) dir)
|
||||||
(format "`%s'" dir))
|
(format "(in `%s')" dir))
|
||||||
'face face2)))))
|
'face face2)))))
|
||||||
|
|
||||||
(defun helm-buffer--format-mode-name (buf)
|
(defun helm-buffer--format-mode-name (buf)
|
||||||
|
@ -1010,14 +1002,12 @@ vertically."
|
||||||
|
|
||||||
(defun helm-buffers-persistent-kill (_buffer)
|
(defun helm-buffers-persistent-kill (_buffer)
|
||||||
(let ((marked (helm-marked-candidates))
|
(let ((marked (helm-marked-candidates))
|
||||||
(sel (helm-get-selection))
|
(sel (helm-get-selection)))
|
||||||
(msg "Buffer `%s' modified, please save it before kill"))
|
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(cl-loop for b in marked
|
(cl-loop for b in marked
|
||||||
do (if (and (buffer-file-name b) (buffer-modified-p b))
|
do (progn
|
||||||
(message msg (buffer-name b))
|
|
||||||
;; We need to preselect each marked because
|
;; We need to preselect each marked because
|
||||||
;; helm-buffers-persistent-kill-1 is deleting
|
;; helm-buffers-persistent-kill is deleting
|
||||||
;; current selection.
|
;; current selection.
|
||||||
(helm-preselect
|
(helm-preselect
|
||||||
(format "^%s"
|
(format "^%s"
|
||||||
|
@ -1035,7 +1025,7 @@ vertically."
|
||||||
(if (or (helm-follow-mode-p)
|
(if (or (helm-follow-mode-p)
|
||||||
(eql current (get-buffer helm-current-buffer))
|
(eql current (get-buffer helm-current-buffer))
|
||||||
(not (eql current (get-buffer candidate))))
|
(not (eql current (get-buffer candidate))))
|
||||||
(display-buffer candidate)
|
(switch-to-buffer candidate)
|
||||||
(if (and helm-persistent-action-display-window
|
(if (and helm-persistent-action-display-window
|
||||||
(window-dedicated-p
|
(window-dedicated-p
|
||||||
(next-window helm-persistent-action-display-window 1)))
|
(next-window helm-persistent-action-display-window 1)))
|
||||||
|
@ -1120,18 +1110,19 @@ Can be used by any source that list buffers."
|
||||||
(cl-assert (not helm-buffers-in-project-p)
|
(cl-assert (not helm-buffers-in-project-p)
|
||||||
nil "You are already browsing this project"))
|
nil "You are already browsing this project"))
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun helm-buffers-quit-and-find-file-fn (source)
|
(defun helm-buffers-quit-and-find-file-fn (source)
|
||||||
(let* ((sel (get-buffer (helm-get-selection nil nil source)))
|
(let* ((sel (helm-get-selection nil nil source))
|
||||||
(bname (and (bufferp sel) (buffer-name sel))))
|
(buf (helm-aand (bufferp sel)
|
||||||
(when bname
|
(get-buffer sel)
|
||||||
|
(buffer-name it))))
|
||||||
|
(when buf
|
||||||
(or (buffer-file-name sel)
|
(or (buffer-file-name sel)
|
||||||
(car (rassoc bname dired-buffers))
|
(car (rassoc buf dired-buffers))
|
||||||
(and (with-current-buffer bname
|
(and (with-current-buffer buf
|
||||||
(eq major-mode 'org-agenda-mode))
|
(eq major-mode 'org-agenda-mode))
|
||||||
org-directory
|
org-directory
|
||||||
(expand-file-name org-directory))
|
(expand-file-name org-directory))
|
||||||
(with-current-buffer bname
|
(with-current-buffer buf
|
||||||
(expand-file-name default-directory))))))
|
(expand-file-name default-directory))))))
|
||||||
|
|
||||||
;;; Candidate Transformers
|
;;; Candidate Transformers
|
|
@ -36,7 +36,7 @@
|
||||||
'global
|
'global
|
||||||
(with-current-buffer (get-buffer "*Faces*")
|
(with-current-buffer (get-buffer "*Faces*")
|
||||||
(buffer-substring
|
(buffer-substring
|
||||||
(next-single-char-property-change (point-min) 'category)
|
(next-single-char-property-change (point-min) 'face)
|
||||||
(point-max))))
|
(point-max))))
|
||||||
(kill-buffer "*Faces*")))
|
(kill-buffer "*Faces*")))
|
||||||
|
|
|
@ -55,10 +55,6 @@ This value can be toggled with
|
||||||
\\<helm-M-x-map>\\[helm-M-x-toggle-short-doc] while in helm-M-x session."
|
\\<helm-M-x-map>\\[helm-M-x-toggle-short-doc] while in helm-M-x session."
|
||||||
:type 'boolean)
|
:type 'boolean)
|
||||||
|
|
||||||
(defcustom helm-M-x-history-transformer-sort t
|
|
||||||
"When nil, do not sort helm-M-x's commands history."
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
|
|
||||||
;;; Faces
|
;;; Faces
|
||||||
;;
|
;;
|
||||||
|
@ -138,59 +134,45 @@ Note that SORT should not be used when fuzzy matching because
|
||||||
fuzzy matching is running its own sort function with a different
|
fuzzy matching is running its own sort function with a different
|
||||||
algorithm."
|
algorithm."
|
||||||
(with-helm-current-buffer
|
(with-helm-current-buffer
|
||||||
(cl-loop with local-map = (helm-M-x-current-mode-map-alist)
|
(cl-loop with max-len = (when helm-M-x-show-short-doc
|
||||||
|
(helm-in-buffer-get-longest-candidate))
|
||||||
|
with local-map = (helm-M-x-current-mode-map-alist)
|
||||||
for cand in candidates
|
for cand in candidates
|
||||||
for local-key = (car (rassq cand local-map))
|
for local-key = (car (rassq cand local-map))
|
||||||
for key = (substitute-command-keys (format "\\[%s]" cand))
|
for key = (substitute-command-keys (format "\\[%s]" cand))
|
||||||
for sym = (intern (if (consp cand) (car cand) cand))
|
for sym = (intern (if (consp cand) (car cand) cand))
|
||||||
for doc = (when helm-M-x-show-short-doc
|
for doc = (when max-len
|
||||||
(helm-get-first-line-documentation (intern-soft cand)))
|
(helm-get-first-line-documentation (intern-soft cand)))
|
||||||
for disp = (if (or (eq sym major-mode)
|
for disp = (if (or (eq sym major-mode)
|
||||||
(and (memq sym minor-mode-list)
|
(and (memq sym minor-mode-list)
|
||||||
(boundp sym)
|
(boundp sym)
|
||||||
(buffer-local-value
|
(buffer-local-value sym helm-current-buffer)))
|
||||||
sym helm-current-buffer)))
|
(propertize cand 'face 'helm-command-active-mode)
|
||||||
(propertize cand 'face 'helm-command-active-mode)
|
cand)
|
||||||
cand)
|
unless (and (null ignore-props) (or (get sym 'helm-only) (get sym 'no-helm-mx)))
|
||||||
unless (and (null ignore-props)
|
|
||||||
(or (get sym 'helm-only) (get sym 'no-helm-mx)
|
|
||||||
(eq sym 'helm-M-x)))
|
|
||||||
collect
|
collect
|
||||||
(cons (cond ((and (string-match "^M-x" key) local-key)
|
(cons (cond ((and (string-match "^M-x" key) local-key)
|
||||||
(propertize
|
(propertize (format "%s%s%s %s"
|
||||||
(format "%s%s%s %s"
|
disp
|
||||||
disp
|
(if doc (make-string (+ 1 (- max-len (length cand))) ? ) "")
|
||||||
(if doc (helm-make-separator cand) "")
|
(if doc (propertize doc 'face 'helm-M-x-short-doc) "")
|
||||||
(if doc
|
(propertize
|
||||||
(propertize
|
" " 'display
|
||||||
doc 'face 'helm-M-x-short-doc)
|
(propertize local-key 'face 'helm-M-x-key)))
|
||||||
"")
|
'match-part disp))
|
||||||
(propertize
|
((string-match "^M-x" key)
|
||||||
" " 'display
|
(propertize (format "%s%s%s"
|
||||||
(propertize local-key 'face 'helm-M-x-key)))
|
disp
|
||||||
'match-part disp))
|
(if doc (make-string (+ 1 (- max-len (length cand))) ? ) "")
|
||||||
((and (string-match "^M-x" key)
|
(if doc (propertize doc 'face 'helm-M-x-short-doc) ""))
|
||||||
(not (string= key "M-x")))
|
'match-part disp))
|
||||||
(propertize
|
(t (propertize (format "%s%s%s %s"
|
||||||
(format "%s%s%s"
|
disp
|
||||||
disp
|
(if doc (make-string (+ 1 (- max-len (length cand))) ? ) "")
|
||||||
(if doc (helm-make-separator cand) "")
|
(if doc (propertize doc 'face 'helm-M-x-short-doc) "")
|
||||||
(if doc
|
(propertize
|
||||||
(propertize
|
" " 'display
|
||||||
doc 'face 'helm-M-x-short-doc)
|
(propertize key 'face 'helm-M-x-key)))
|
||||||
""))
|
|
||||||
'match-part disp))
|
|
||||||
(t (propertize
|
|
||||||
(format "%s%s%s %s"
|
|
||||||
disp
|
|
||||||
(if doc (helm-make-separator cand) "")
|
|
||||||
(if doc
|
|
||||||
(propertize
|
|
||||||
doc 'face 'helm-M-x-short-doc)
|
|
||||||
"")
|
|
||||||
(propertize
|
|
||||||
" " 'display
|
|
||||||
(propertize key 'face 'helm-M-x-key)))
|
|
||||||
'match-part disp)))
|
'match-part disp)))
|
||||||
cand)
|
cand)
|
||||||
into ls
|
into ls
|
||||||
|
@ -262,7 +244,7 @@ algorithm."
|
||||||
(defclass helm-M-x-class (helm-source-in-buffer helm-type-command)
|
(defclass helm-M-x-class (helm-source-in-buffer helm-type-command)
|
||||||
((requires-pattern :initform 0)
|
((requires-pattern :initform 0)
|
||||||
(must-match :initform t)
|
(must-match :initform t)
|
||||||
(filtered-candidate-transformer :initform #'helm-M-x-transformer)
|
(filtered-candidate-transformer :initform 'helm-M-x-transformer-no-sort)
|
||||||
(persistent-help :initform "Describe this command")
|
(persistent-help :initform "Describe this command")
|
||||||
(help-message :initform 'helm-M-x-help-message)
|
(help-message :initform 'helm-M-x-help-message)
|
||||||
(nomark :initform t)
|
(nomark :initform t)
|
||||||
|
@ -283,19 +265,23 @@ algorithm."
|
||||||
(defun helm-M-x-read-extended-command (collection &optional predicate history)
|
(defun helm-M-x-read-extended-command (collection &optional predicate history)
|
||||||
"Read or execute action on command name in COLLECTION or HISTORY.
|
"Read or execute action on command name in COLLECTION or HISTORY.
|
||||||
|
|
||||||
Helm completion is not provided when executing or defining kbd macros.
|
When `helm-M-x-use-completion-styles' is used, Emacs
|
||||||
|
`completion-styles' mechanism is used, otherwise standard helm
|
||||||
|
completion and helm fuzzy matching are used together.
|
||||||
|
|
||||||
Arg COLLECTION should be an `obarray'.
|
Helm completion is not provided when executing or defining kbd
|
||||||
Arg PREDICATE is a function that default to `commandp'.
|
macros.
|
||||||
Arg HISTORY default to `extended-command-history'."
|
|
||||||
|
Arg COLLECTION should be an `obarray' but can be any object
|
||||||
|
suitable for `try-completion'. Arg PREDICATE is a function that
|
||||||
|
default to `commandp' see also `try-completion'. Arg HISTORY
|
||||||
|
default to `extended-command-history'."
|
||||||
(setq helm--mode-line-display-prefarg t)
|
(setq helm--mode-line-display-prefarg t)
|
||||||
(let* ((pred (or predicate #'commandp))
|
(let* ((pred (or predicate #'commandp))
|
||||||
(helm-fuzzy-sort-fn (lambda (candidates _source)
|
(helm-fuzzy-sort-fn (lambda (candidates _source)
|
||||||
(if helm-M-x-history-transformer-sort
|
;; Sort on real candidate otherwise
|
||||||
;; Sort on real candidate otherwise
|
;; "symbol (<binding>)" is used when sorting.
|
||||||
;; "symbol (<binding>)" is used when sorting.
|
(helm-fuzzy-matching-default-sort-fn-1 candidates t)))
|
||||||
(helm-fuzzy-matching-default-sort-fn-1 candidates t)
|
|
||||||
candidates)))
|
|
||||||
(sources `(,(helm-make-source "Emacs Commands history" 'helm-M-x-class
|
(sources `(,(helm-make-source "Emacs Commands history" 'helm-M-x-class
|
||||||
:data (lambda ()
|
:data (lambda ()
|
||||||
(helm-comp-read-get-candidates
|
(helm-comp-read-get-candidates
|
||||||
|
@ -307,10 +293,6 @@ Arg HISTORY default to `extended-command-history'."
|
||||||
;; Ensure using empty string to
|
;; Ensure using empty string to
|
||||||
;; not defeat helm matching fns [1]
|
;; not defeat helm matching fns [1]
|
||||||
pred nil nil ""))
|
pred nil nil ""))
|
||||||
:filtered-candidate-transformer
|
|
||||||
(if helm-M-x-history-transformer-sort
|
|
||||||
#'helm-M-x-transformer
|
|
||||||
#'helm-M-x-transformer-no-sort)
|
|
||||||
:fuzzy-match helm-M-x-fuzzy-match)
|
:fuzzy-match helm-M-x-fuzzy-match)
|
||||||
,(helm-make-source "Emacs Commands" 'helm-M-x-class
|
,(helm-make-source "Emacs Commands" 'helm-M-x-class
|
||||||
:data (lambda ()
|
:data (lambda ()
|
||||||
|
@ -318,11 +300,16 @@ Arg HISTORY default to `extended-command-history'."
|
||||||
;; [1] Same comment as above.
|
;; [1] Same comment as above.
|
||||||
collection pred nil nil ""))
|
collection pred nil nil ""))
|
||||||
:fuzzy-match helm-M-x-fuzzy-match)))
|
:fuzzy-match helm-M-x-fuzzy-match)))
|
||||||
(prompt (concat (helm-acase helm-M-x-prefix-argument
|
(prompt (concat (cond
|
||||||
(- "-")
|
((eq helm-M-x-prefix-argument '-) "- ")
|
||||||
((guard (and (consp it) (car it)))
|
((and (consp helm-M-x-prefix-argument)
|
||||||
(if (eq guard 4) "C-u " (format "%d " guard)))
|
(eq (car helm-M-x-prefix-argument) 4))
|
||||||
((guard (integerp it)) (format "%d " it)))
|
"C-u ")
|
||||||
|
((and (consp helm-M-x-prefix-argument)
|
||||||
|
(integerp (car helm-M-x-prefix-argument)))
|
||||||
|
(format "%d " (car helm-M-x-prefix-argument)))
|
||||||
|
((integerp helm-M-x-prefix-argument)
|
||||||
|
(format "%d " helm-M-x-prefix-argument)))
|
||||||
"M-x ")))
|
"M-x ")))
|
||||||
(setq helm-M-x--timer (run-at-time 1 0.1 #'helm-M-x--notify-prefix-arg))
|
(setq helm-M-x--timer (run-at-time 1 0.1 #'helm-M-x--notify-prefix-arg))
|
||||||
;; Fix Bug#2250, add `helm-move-selection-after-hook' which
|
;; Fix Bug#2250, add `helm-move-selection-after-hook' which
|
|
@ -54,7 +54,7 @@ Helm buffer."
|
||||||
(defcustom helm-dabbrev-related-buffer-fn #'helm-dabbrev--same-major-mode-p
|
(defcustom helm-dabbrev-related-buffer-fn #'helm-dabbrev--same-major-mode-p
|
||||||
"A function that decide if a buffer to search in its related to `current-buffer'.
|
"A function that decide if a buffer to search in its related to `current-buffer'.
|
||||||
|
|
||||||
This is currently determined by comparing `major-mode' of the
|
This is actually determined by comparing `major-mode' of the
|
||||||
buffer to search and the `current-buffer'.
|
buffer to search and the `current-buffer'.
|
||||||
|
|
||||||
The function take one arg, the buffer which is current, look at
|
The function take one arg, the buffer which is current, look at
|
|
@ -31,8 +31,7 @@
|
||||||
["Recent Files" helm-recentf t]
|
["Recent Files" helm-recentf t]
|
||||||
["Locate" helm-locate t]
|
["Locate" helm-locate t]
|
||||||
["Search Files with find" helm-find t]
|
["Search Files with find" helm-find t]
|
||||||
["Bookmarks" helm-filtered-bookmarks t]
|
["Bookmarks" helm-filtered-bookmarks t])
|
||||||
["Locate library" helm-locate-library t])
|
|
||||||
("Buffers"
|
("Buffers"
|
||||||
["Find buffers" helm-buffers-list t])
|
["Find buffers" helm-buffers-list t])
|
||||||
("Projects"
|
("Projects"
|
||||||
|
@ -48,9 +47,8 @@
|
||||||
["Emacs Manual index" helm-info-emacs t]
|
["Emacs Manual index" helm-info-emacs t]
|
||||||
["Gnus Manual index" helm-info-gnus t]
|
["Gnus Manual index" helm-info-gnus t]
|
||||||
["Helm documentation" helm-documentation t])
|
["Helm documentation" helm-documentation t])
|
||||||
("Packages"
|
("Elpa"
|
||||||
["Elisp packages" helm-packages t]
|
["Elisp packages" helm-packages t])
|
||||||
["Finder" helm-finder t])
|
|
||||||
("Tools"
|
("Tools"
|
||||||
["Occur" helm-occur t]
|
["Occur" helm-occur t]
|
||||||
["Grep current directory with AG" helm-do-grep-ag t]
|
["Grep current directory with AG" helm-do-grep-ag t]
|
|
@ -33,9 +33,6 @@
|
||||||
(declare-function helm-comp-read "helm-mode")
|
(declare-function helm-comp-read "helm-mode")
|
||||||
(declare-function helm-M-x-transformer-no-sort-no-props "helm-command")
|
(declare-function helm-M-x-transformer-no-sort-no-props "helm-command")
|
||||||
(defvar helm-M-x-show-short-doc)
|
(defvar helm-M-x-show-short-doc)
|
||||||
(defvar completions-detailed)
|
|
||||||
(defvar helm-completions-detailed)
|
|
||||||
|
|
||||||
|
|
||||||
;;; Customizable values
|
;;; Customizable values
|
||||||
|
|
||||||
|
@ -160,9 +157,9 @@ display."
|
||||||
;; Called each time cursor move in helm-buffer.
|
;; Called each time cursor move in helm-buffer.
|
||||||
(defun helm-show-completion ()
|
(defun helm-show-completion ()
|
||||||
(with-helm-current-buffer
|
(with-helm-current-buffer
|
||||||
(helm-aif (helm-get-selection)
|
(overlay-put helm-show-completion-overlay
|
||||||
(overlay-put helm-show-completion-overlay
|
'display (substring-no-properties
|
||||||
'display (substring-no-properties it)))))
|
(helm-get-selection)))))
|
||||||
|
|
||||||
(defun helm-show-completion-init-overlay (beg end)
|
(defun helm-show-completion-init-overlay (beg end)
|
||||||
(setq helm-show-completion-overlay (make-overlay beg end))
|
(setq helm-show-completion-overlay (make-overlay beg end))
|
||||||
|
@ -209,9 +206,6 @@ If `helm-turn-on-show-completion' is nil do nothing."
|
||||||
'helm-display-function
|
'helm-display-function
|
||||||
(or helm-show-completion-display-function
|
(or helm-show-completion-display-function
|
||||||
'helm-default-display-buffer))
|
'helm-default-display-buffer))
|
||||||
(with-helm-after-update-hook
|
|
||||||
;; Show immediately first candidate as soon as helm popup.
|
|
||||||
(helm-show-completion))
|
|
||||||
(helm-show-completion-init-overlay ,beg ,end)
|
(helm-show-completion-init-overlay ,beg ,end)
|
||||||
,@body)
|
,@body)
|
||||||
,@body)
|
,@body)
|
||||||
|
@ -298,10 +292,13 @@ Return a cons (beg . end)."
|
||||||
(when (and pos (< (point) pos))
|
(when (and pos (< (point) pos))
|
||||||
(push-mark pos t t))))
|
(push-mark pos t t))))
|
||||||
|
|
||||||
|
(defvar helm-lisp-completion--cache nil)
|
||||||
|
(defvar helm-lgst-len nil)
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun helm-lisp-completion-at-point ()
|
(defun helm-lisp-completion-at-point ()
|
||||||
"Preconfigured Helm for Lisp symbol completion at point."
|
"Preconfigured Helm for Lisp symbol completion at point."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
(setq helm-lgst-len 0)
|
||||||
(let* ((target (helm-thing-before-point))
|
(let* ((target (helm-thing-before-point))
|
||||||
(beg (car (helm-bounds-of-thing-before-point)))
|
(beg (car (helm-bounds-of-thing-before-point)))
|
||||||
(end (point))
|
(end (point))
|
||||||
|
@ -314,12 +311,17 @@ Return a cons (beg . end)."
|
||||||
(helm-quit-if-no-candidate t)
|
(helm-quit-if-no-candidate t)
|
||||||
(helm-execute-action-at-once-if-one t)
|
(helm-execute-action-at-once-if-one t)
|
||||||
(enable-recursive-minibuffers t))
|
(enable-recursive-minibuffers t))
|
||||||
|
(setq helm-lisp-completion--cache (cl-loop for sym in candidates
|
||||||
|
for len = (length sym)
|
||||||
|
when (> len helm-lgst-len)
|
||||||
|
do (setq helm-lgst-len len)
|
||||||
|
collect sym))
|
||||||
(if candidates
|
(if candidates
|
||||||
(with-helm-show-completion beg end
|
(with-helm-show-completion beg end
|
||||||
;; Overlay is initialized now in helm-current-buffer.
|
;; Overlay is initialized now in helm-current-buffer.
|
||||||
(helm
|
(helm
|
||||||
:sources (helm-build-in-buffer-source "Lisp completion"
|
:sources (helm-build-in-buffer-source "Lisp completion"
|
||||||
:data candidates
|
:data helm-lisp-completion--cache
|
||||||
:persistent-action `(helm-lisp-completion-persistent-action .
|
:persistent-action `(helm-lisp-completion-persistent-action .
|
||||||
,(and (eq helm-elisp-help-function
|
,(and (eq helm-elisp-help-function
|
||||||
'helm-elisp-show-doc-modeline)
|
'helm-elisp-show-doc-modeline)
|
||||||
|
@ -358,17 +360,17 @@ other window according to the value of
|
||||||
(helm-elisp-show-help "Toggle show help for the symbol")))
|
(helm-elisp-show-help "Toggle show help for the symbol")))
|
||||||
|
|
||||||
(defun helm-elisp--show-help-1 (candidate &optional name)
|
(defun helm-elisp--show-help-1 (candidate &optional name)
|
||||||
(helm-acase (intern-soft candidate)
|
(let ((sym (intern-soft candidate)))
|
||||||
((guard (and (fboundp it) (boundp it)))
|
(pcase sym
|
||||||
(if (member name `(,helm-describe-function-function
|
((and (pred fboundp) (pred boundp))
|
||||||
,helm-describe-variable-function))
|
(if (member name `(,helm-describe-function-function ,helm-describe-variable-function))
|
||||||
(funcall (intern (format "helm-%s" name)) it)
|
(funcall (intern (format "helm-%s" name)) sym)
|
||||||
;; When there is no way to know what to describe
|
;; When there is no way to know what to describe
|
||||||
;; prefer describe-function.
|
;; prefer describe-function.
|
||||||
(helm-describe-function it)))
|
(helm-describe-function sym)))
|
||||||
((guard (fboundp it)) (helm-describe-function it))
|
((pred fboundp) (helm-describe-function sym))
|
||||||
((guard (boundp it)) (helm-describe-variable it))
|
((pred boundp) (helm-describe-variable sym))
|
||||||
((guard (facep it)) (helm-describe-face it))))
|
((pred facep) (helm-describe-face sym)))))
|
||||||
|
|
||||||
(defun helm-elisp-show-help (candidate &optional name)
|
(defun helm-elisp-show-help (candidate &optional name)
|
||||||
"Show full help for the function CANDIDATE.
|
"Show full help for the function CANDIDATE.
|
||||||
|
@ -392,16 +394,17 @@ the same time to variable and a function."
|
||||||
(defun helm-lisp-completion-transformer (candidates _source)
|
(defun helm-lisp-completion-transformer (candidates _source)
|
||||||
"Helm candidates transformer for Lisp completion."
|
"Helm candidates transformer for Lisp completion."
|
||||||
(cl-loop for c in candidates
|
(cl-loop for c in candidates
|
||||||
for sym = (intern c)
|
for sym = (intern c)
|
||||||
for annot = (helm-acase sym
|
for annot = (pcase sym
|
||||||
((guard (commandp it)) " (Com)")
|
((pred commandp) " (Com)")
|
||||||
((guard (class-p it)) " (Class)")
|
((pred class-p) " (Class)")
|
||||||
((guard (cl-generic-p it)) " (Gen)")
|
((pred cl-generic-p) " (Gen)")
|
||||||
((guard (fboundp it)) " (Fun)")
|
((pred fboundp) " (Fun)")
|
||||||
((guard (boundp it)) " (Var)")
|
((pred boundp) " (Var)")
|
||||||
((guard (facep it)) " (Face)"))
|
((pred facep) " (Face)"))
|
||||||
collect (cons (concat c (helm-make-separator c) annot) c) into lst
|
for spaces = (make-string (- helm-lgst-len (length c)) ? )
|
||||||
finally return (sort lst #'helm-generic-sort-fn)))
|
collect (cons (concat c spaces annot) c) into lst
|
||||||
|
finally return (sort lst #'helm-generic-sort-fn)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(cl-defun helm-get-first-line-documentation (sym &optional
|
(cl-defun helm-get-first-line-documentation (sym &optional
|
||||||
|
@ -412,37 +415,31 @@ If SYM is not documented, return \"Not documented\".
|
||||||
Argument NAME allows specifiying what function to use to display
|
Argument NAME allows specifiying what function to use to display
|
||||||
documentation when SYM name is the same for function and variable."
|
documentation when SYM name is the same for function and variable."
|
||||||
(let ((doc (condition-case _err
|
(let ((doc (condition-case _err
|
||||||
(helm-acase sym
|
(pcase sym
|
||||||
((guard (class-p it))
|
((pred class-p) (cl--class-docstring (cl--find-class sym)))
|
||||||
(cl--class-docstring (cl--find-class it)))
|
((and (pred fboundp) (pred boundp))
|
||||||
((guard (and (fboundp it) (boundp it)))
|
(pcase name
|
||||||
(if (string= name "describe-variable")
|
("describe-function"
|
||||||
(documentation-property it 'variable-documentation t)
|
(documentation sym t))
|
||||||
(documentation it t)))
|
("describe-variable"
|
||||||
((guard (custom-theme-p it))
|
(documentation-property sym 'variable-documentation t))
|
||||||
(documentation-property it 'theme-documentation t))
|
(_ (documentation sym t))))
|
||||||
((guard (and (helm-group-p it) (not (fboundp it))))
|
((pred custom-theme-p)
|
||||||
(documentation-property it 'group-documentation t))
|
(documentation-property sym 'theme-documentation t))
|
||||||
((guard (fboundp it))
|
((pred helm-group-p) (documentation-property
|
||||||
(documentation it t))
|
sym 'group-documentation t))
|
||||||
((guard (boundp it))
|
((pred fboundp) (documentation sym t))
|
||||||
(documentation-property it 'variable-documentation t))
|
((pred boundp) (documentation-property
|
||||||
((guard (facep it)) (face-documentation it)))
|
sym 'variable-documentation t))
|
||||||
|
((pred facep) (face-documentation sym)))
|
||||||
(void-function "Void function -- Not documented"))))
|
(void-function "Void function -- Not documented"))))
|
||||||
(if (and doc (not (string= doc ""))
|
(if (and doc (not (string= doc ""))
|
||||||
;; `documentation' return "\n\n(args...)"
|
;; `documentation' return "\n\n(args...)"
|
||||||
;; for CL-style functions.
|
;; for CL-style functions.
|
||||||
(not (string-match-p "\\`\n\n" doc)))
|
(not (string-match-p "\\`\n\n" doc)))
|
||||||
;; Some commands specify key bindings or keymap in their first line,
|
;; Some commands specify key bindings in their first line.
|
||||||
;; e.g.: "\<hexl-mode-map>A mode for editing binary [...]. As a result
|
|
||||||
;; (substitute-command-keys doc) returns a string like "\nUses
|
|
||||||
;; keymap...\nFirst line docstring. See
|
|
||||||
;; <https://debbugs.gnu.org/70163>.
|
|
||||||
(truncate-string-to-width
|
(truncate-string-to-width
|
||||||
(helm-acase (split-string (substitute-command-keys doc) "\n")
|
(substitute-command-keys (car (split-string doc "\n")))
|
||||||
((guard (and (string= (car it) "") (cdr it)))
|
|
||||||
(cadr guard))
|
|
||||||
(t (car it)))
|
|
||||||
end-column nil nil t)
|
end-column nil nil t)
|
||||||
(if (or (symbol-function sym) (boundp sym) (facep sym) (helm-group-p sym))
|
(if (or (symbol-function sym) (boundp sym) (facep sym) (helm-group-p sym))
|
||||||
"Not documented"
|
"Not documented"
|
||||||
|
@ -460,7 +457,7 @@ documentation when SYM name is the same for function and variable."
|
||||||
"Preconfigured Helm to complete file name at point."
|
"Preconfigured Helm to complete file name at point."
|
||||||
(interactive)
|
(interactive)
|
||||||
(require 'helm-mode)
|
(require 'helm-mode)
|
||||||
(let* ((tap (or (thing-at-point 'filename t) ""))
|
(let* ((tap (or (thing-at-point 'filename) ""))
|
||||||
beg
|
beg
|
||||||
(init (and tap
|
(init (and tap
|
||||||
(or force
|
(or force
|
||||||
|
@ -469,7 +466,8 @@ documentation when SYM name is the same for function and variable."
|
||||||
(search-backward tap (pos-bol) t)
|
(search-backward tap (pos-bol) t)
|
||||||
(setq beg (point))
|
(setq beg (point))
|
||||||
(looking-back "[^'`( ]" (1- (point)))))
|
(looking-back "[^'`( ]" (1- (point)))))
|
||||||
(expand-file-name tap)))
|
(expand-file-name
|
||||||
|
(substring-no-properties tap))))
|
||||||
(end (point))
|
(end (point))
|
||||||
(helm-quit-if-no-candidate t)
|
(helm-quit-if-no-candidate t)
|
||||||
(helm-execute-action-at-once-if-one t)
|
(helm-execute-action-at-once-if-one t)
|
||||||
|
@ -481,7 +479,6 @@ documentation when SYM name is the same for function and variable."
|
||||||
(delete-region beg end) (insert (if (string-match "^~" tap)
|
(delete-region beg end) (insert (if (string-match "^~" tap)
|
||||||
(abbreviate-file-name completion)
|
(abbreviate-file-name completion)
|
||||||
completion)))))
|
completion)))))
|
||||||
(make-obsolete 'helm-complete-file-name-at-point 'helm-find-files "3.9.6")
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun helm-lisp-indent ()
|
(defun helm-lisp-indent ()
|
||||||
|
@ -493,6 +490,20 @@ documentation when SYM name is the same for function and variable."
|
||||||
tab-always-indent)))
|
tab-always-indent)))
|
||||||
(indent-for-tab-command current-prefix-arg)))
|
(indent-for-tab-command current-prefix-arg)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun helm-lisp-completion-or-file-name-at-point ()
|
||||||
|
"Preconfigured Helm to complete Lisp symbol or filename at point.
|
||||||
|
Filename completion happens if string start after or between a
|
||||||
|
double quote."
|
||||||
|
(interactive)
|
||||||
|
(let* ((tap (thing-at-point 'filename)))
|
||||||
|
(if (and tap (save-excursion
|
||||||
|
(end-of-line)
|
||||||
|
(search-backward tap (pos-bol) t)
|
||||||
|
(looking-back "[^'`( ]" (1- (point)))))
|
||||||
|
(helm-complete-file-name-at-point)
|
||||||
|
(helm-lisp-completion-at-point))))
|
||||||
|
|
||||||
|
|
||||||
;;; Apropos
|
;;; Apropos
|
||||||
;;
|
;;
|
||||||
|
@ -532,17 +543,18 @@ is only used to test DEFAULT."
|
||||||
|
|
||||||
(defun helm-apropos-short-doc-transformer (candidates _source)
|
(defun helm-apropos-short-doc-transformer (candidates _source)
|
||||||
(if helm-apropos-show-short-doc
|
(if helm-apropos-show-short-doc
|
||||||
(cl-loop for cand in candidates
|
(cl-loop with max-len = (helm-in-buffer-get-longest-candidate)
|
||||||
|
for cand in candidates
|
||||||
for doc = (helm-get-first-line-documentation (intern-soft cand))
|
for doc = (helm-get-first-line-documentation (intern-soft cand))
|
||||||
collect (cons (format "%s%s%s"
|
collect (cons (format "%s%s%s"
|
||||||
cand
|
cand
|
||||||
(if doc
|
(if doc
|
||||||
(helm-make-separator cand)
|
(make-string (+ 1 (if (zerop max-len)
|
||||||
|
max-len
|
||||||
|
(- max-len (string-width cand))))
|
||||||
|
? )
|
||||||
"")
|
"")
|
||||||
(if doc
|
(if doc (propertize doc 'face 'helm-M-x-short-doc) ""))
|
||||||
(propertize
|
|
||||||
doc 'face 'helm-M-x-short-doc)
|
|
||||||
""))
|
|
||||||
cand))
|
cand))
|
||||||
candidates))
|
candidates))
|
||||||
|
|
||||||
|
@ -746,23 +758,23 @@ is only used to test DEFAULT."
|
||||||
("Info lookup" . helm-info-lookup-symbol))))
|
("Info lookup" . helm-info-lookup-symbol))))
|
||||||
|
|
||||||
(defun helm-info-lookup-fallback-source (candidate)
|
(defun helm-info-lookup-fallback-source (candidate)
|
||||||
(cl-multiple-value-bind (fn src-name)
|
(let ((sym (helm-symbolify candidate))
|
||||||
(helm-acase (helm-symbolify candidate)
|
src-name fn)
|
||||||
((guard (class-p it))
|
(cond ((class-p sym)
|
||||||
(list #'helm-describe-function
|
(setq fn #'helm-describe-function
|
||||||
"Describe class"))
|
src-name "Describe class"))
|
||||||
((guard (cl-generic-p it))
|
((cl-generic-p sym)
|
||||||
(list #'helm-describe-function
|
(setq fn #'helm-describe-function
|
||||||
"Describe generic function"))
|
src-name "Describe generic function"))
|
||||||
((guard (fboundp it))
|
((fboundp sym)
|
||||||
(list #'helm-describe-function
|
(setq fn #'helm-describe-function
|
||||||
"Describe function"))
|
src-name "Describe function"))
|
||||||
((guard (facep it))
|
((facep sym)
|
||||||
(list #'helm-describe-face
|
(setq fn #'helm-describe-face
|
||||||
"Describe face"))
|
src-name "Describe face"))
|
||||||
(t
|
(t
|
||||||
(list #'helm-describe-variable
|
(setq fn #'helm-describe-variable
|
||||||
"Describe variable")))
|
src-name "Describe variable")))
|
||||||
(helm-build-sync-source src-name
|
(helm-build-sync-source src-name
|
||||||
:candidates (list candidate)
|
:candidates (list candidate)
|
||||||
:persistent-action (lambda (candidate)
|
:persistent-action (lambda (candidate)
|
||||||
|
@ -798,10 +810,7 @@ is only used to test DEFAULT."
|
||||||
|
|
||||||
(defun helm-apropos-get-default ()
|
(defun helm-apropos-get-default ()
|
||||||
(with-syntax-table emacs-lisp-mode-syntax-table
|
(with-syntax-table emacs-lisp-mode-syntax-table
|
||||||
(symbol-name (intern-soft
|
(symbol-name (intern-soft (thing-at-point 'symbol)))))
|
||||||
(helm-aand (thing-at-point 'symbol t)
|
|
||||||
(replace-regexp-in-string "\\`[~=]" "" it)
|
|
||||||
(replace-regexp-in-string "[~=]\\'" "" it))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun helm-apropos (default)
|
(defun helm-apropos (default)
|
||||||
|
@ -844,19 +853,19 @@ a string, i.e. the `symbol-name' of any existing symbol."
|
||||||
:persistent-help "Toggle describe function / C-u C-j: Toggle advice"))
|
:persistent-help "Toggle describe function / C-u C-j: Toggle advice"))
|
||||||
|
|
||||||
(defun helm-advice-candidates ()
|
(defun helm-advice-candidates ()
|
||||||
(cl-loop for fname in ad-advised-functions
|
(cl-loop for (fname) in ad-advised-functions
|
||||||
for function = (intern fname)
|
for function = (intern fname)
|
||||||
append
|
append
|
||||||
(cl-loop for class in ad-advice-classes append
|
(cl-loop for class in ad-advice-classes append
|
||||||
(cl-loop for advice in (ad-get-advice-info-field function class)
|
(cl-loop for advice in (ad-get-advice-info-field function class)
|
||||||
for enabled = (ad-advice-enabled advice)
|
for enabled = (ad-advice-enabled advice)
|
||||||
collect
|
collect
|
||||||
(cons (format
|
(cons (format
|
||||||
"%s %s %s"
|
"%s %s %s"
|
||||||
(if enabled "Enabled " "Disabled")
|
(if enabled "Enabled " "Disabled")
|
||||||
(propertize fname 'face 'font-lock-function-name-face)
|
(propertize fname 'face 'font-lock-function-name-face)
|
||||||
(ad-make-single-advice-docstring advice class nil))
|
(ad-make-single-advice-docstring advice class nil))
|
||||||
(list function class advice))))))
|
(list function class advice))))))
|
||||||
|
|
||||||
(defun helm-advice-persistent-action (func-class-advice)
|
(defun helm-advice-persistent-action (func-class-advice)
|
||||||
(if current-prefix-arg
|
(if current-prefix-arg
|
||||||
|
@ -893,76 +902,41 @@ a string, i.e. the `symbol-name' of any existing symbol."
|
||||||
;;; Locate elisp library
|
;;; Locate elisp library
|
||||||
;;
|
;;
|
||||||
;;
|
;;
|
||||||
(defvar helm--locate-library-cache nil)
|
|
||||||
(defvar helm--locate-library-doc-cache (make-hash-table :test 'equal))
|
|
||||||
(defun helm-locate-library-scan-list ()
|
(defun helm-locate-library-scan-list ()
|
||||||
(cl-loop for dir in load-path
|
(cl-loop for dir in load-path
|
||||||
|
with load-suffixes = '(".el")
|
||||||
when (file-directory-p dir)
|
when (file-directory-p dir)
|
||||||
nconc (directory-files
|
append (directory-files
|
||||||
dir nil (concat (regexp-opt (find-library-suffixes)) "\\'"))))
|
dir t (concat (regexp-opt (get-load-suffixes))
|
||||||
|
"\\'"))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun helm-locate-library (&optional arg)
|
(defun helm-locate-library ()
|
||||||
"Preconfigured helm to locate elisp libraries.
|
"Preconfigured helm to locate elisp libraries."
|
||||||
|
(interactive)
|
||||||
When `completions-detailed' or `helm-completions-detailed' is non
|
(helm :sources (helm-build-in-buffer-source "Elisp libraries (Scan)"
|
||||||
nil, a description of libraries is provided. The libraries are
|
:data #'helm-locate-library-scan-list
|
||||||
partially cached in the variables
|
:fuzzy-match helm-locate-library-fuzzy-match
|
||||||
`helm--locate-library-doc-cache' and
|
:keymap helm-generic-files-map
|
||||||
`helm--locate-library-cache'. TIP: You can make these vars
|
:search (unless helm-locate-library-fuzzy-match
|
||||||
persistent for faster start with the psession package, using M-x
|
(lambda (regexp)
|
||||||
psession-make-persistent-variable. NOTE: The caches affect as
|
(re-search-forward
|
||||||
well `find-libray' and `locate-library' when `helm-mode' is
|
(if helm-ff-transformer-show-only-basename
|
||||||
enabled and `completions-detailed' is non nil. There is no need
|
(replace-regexp-in-string
|
||||||
to refresh the caches, they will be updated automatically if some
|
"\\`\\^" "" regexp)
|
||||||
new libraries are found, however when a library update its
|
regexp)
|
||||||
headers and the description change you can reset the caches with
|
nil t)))
|
||||||
a prefix arg."
|
:match-part (lambda (candidate)
|
||||||
(interactive "P")
|
(with-helm-buffer
|
||||||
(let (done)
|
(if helm-ff-transformer-show-only-basename
|
||||||
(when arg
|
(helm-basename candidate) candidate)))
|
||||||
(setq helm--locate-library-cache nil)
|
:filter-one-by-one (lambda (c)
|
||||||
(clrhash helm--locate-library-doc-cache))
|
(with-helm-buffer
|
||||||
(helm :sources
|
(if helm-ff-transformer-show-only-basename
|
||||||
(helm-build-in-buffer-source "Elisp libraries (Scan)"
|
(cons (helm-basename c) c) c)))
|
||||||
:data #'helm-locate-library-scan-list
|
:action (helm-actions-from-type-file))
|
||||||
:fuzzy-match helm-locate-library-fuzzy-match
|
:ff-transformer-show-only-basename nil
|
||||||
:keymap helm-generic-files-map
|
:buffer "*helm locate library*"))
|
||||||
:candidate-transformer
|
|
||||||
(lambda (candidates)
|
|
||||||
(cl-loop with reporter = (unless done
|
|
||||||
(make-progress-reporter
|
|
||||||
"Scanning libraries..." 0 (length candidates)))
|
|
||||||
with lgst = (helm-in-buffer-get-longest-candidate)
|
|
||||||
for c in candidates
|
|
||||||
for count from 0
|
|
||||||
for bn = (helm-basename c 2)
|
|
||||||
for sep = (helm-make-separator bn lgst)
|
|
||||||
for path = (or (assoc-default bn helm--locate-library-cache)
|
|
||||||
;; A lock file in LOAD-PATH (bug#2626).
|
|
||||||
(unless (string-match "\\`\\.#" bn)
|
|
||||||
(let ((p (find-library-name bn)))
|
|
||||||
(push (cons bn p) helm--locate-library-cache)
|
|
||||||
p)))
|
|
||||||
for doc = (and path
|
|
||||||
(or completions-detailed helm-completions-detailed)
|
|
||||||
(or (gethash bn helm--locate-library-doc-cache)
|
|
||||||
(puthash bn (helm-locate-lib-get-summary path)
|
|
||||||
helm--locate-library-doc-cache)))
|
|
||||||
for disp = (and path
|
|
||||||
(if (and doc
|
|
||||||
(or completions-detailed helm-completions-detailed))
|
|
||||||
(helm-aand (propertize doc 'face 'font-lock-warning-face)
|
|
||||||
(propertize " " 'display (concat sep it))
|
|
||||||
(concat bn it))
|
|
||||||
bn))
|
|
||||||
when (and disp path)
|
|
||||||
collect (cons disp path)
|
|
||||||
when reporter do (progress-reporter-update reporter count)
|
|
||||||
finally do (setq done t)))
|
|
||||||
:action (helm-actions-from-type-file))
|
|
||||||
:buffer "*helm locate library*")))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Modify variables from Helm
|
;;; Modify variables from Helm
|
||||||
;;
|
;;
|
|
@ -86,18 +86,14 @@
|
||||||
uid 'face 'font-lock-warning-face))
|
uid 'face 'font-lock-warning-face))
|
||||||
key)))
|
key)))
|
||||||
|
|
||||||
(cl-defun helm-epa--select-keys (prompt keys)
|
(defun helm-epa--select-keys (prompt keys)
|
||||||
"A helm replacement for `epa--select-keys'."
|
"A helm replacement for `epa--select-keys'."
|
||||||
(let ((result (helm :sources (helm-make-source "Epa select keys" 'helm-epa
|
(let ((result (helm :sources (helm-make-source "Epa select keys" 'helm-epa
|
||||||
:candidates (lambda ()
|
:candidates (lambda ()
|
||||||
(helm-epa-get-key-list keys))
|
(helm-epa-get-key-list keys)))
|
||||||
:action (lambda (_candidate)
|
|
||||||
(helm-marked-candidates)))
|
|
||||||
:prompt (and prompt (helm-epa--format-prompt prompt))
|
:prompt (and prompt (helm-epa--format-prompt prompt))
|
||||||
:buffer "*helm epa*")))
|
:buffer "*helm epa*")))
|
||||||
(if (or (equal result "") (null result))
|
(unless (equal result "")
|
||||||
(cl-return-from helm-epa--select-keys
|
|
||||||
(error "No keys selected, aborting"))
|
|
||||||
result)))
|
result)))
|
||||||
|
|
||||||
(defun helm-epa--format-prompt (prompt)
|
(defun helm-epa--format-prompt (prompt)
|
||||||
|
@ -108,23 +104,13 @@
|
||||||
(replace-regexp-in-string "\\.[\t ]*\\'" "" (cadr split)))
|
(replace-regexp-in-string "\\.[\t ]*\\'" "" (cadr split)))
|
||||||
(format "%s: " (replace-regexp-in-string "\\.[\t ]*\\'" "" (car split))))))
|
(format "%s: " (replace-regexp-in-string "\\.[\t ]*\\'" "" (car split))))))
|
||||||
|
|
||||||
(defun helm-epa--read-signature-type-help ()
|
|
||||||
(with-temp-buffer
|
|
||||||
(save-excursion
|
|
||||||
(insert
|
|
||||||
"n: Create a normal signature)\n"
|
|
||||||
"c: Create a cleartext signature)\n"
|
|
||||||
"d: Create a detached signature)"))
|
|
||||||
(while (re-search-forward "^\\(.\\):" nil t)
|
|
||||||
(helm-add-face-text-properties (match-beginning 1) (match-end 1)
|
|
||||||
'font-lock-variable-name-face))
|
|
||||||
(buffer-string)))
|
|
||||||
|
|
||||||
(defun helm-epa--read-signature-type ()
|
(defun helm-epa--read-signature-type ()
|
||||||
"A helm replacement for `epa--read-signature-type'."
|
"A helm replacement for `epa--read-signature-type'."
|
||||||
(let ((answer (helm-read-answer "Signature type? [n,c,d,h]"
|
(let ((answer (helm-read-answer "Signature type:
|
||||||
'("n" "c" "d")
|
(n - Create a normal signature)
|
||||||
#'helm-epa--read-signature-type-help)))
|
(c - Create a cleartext signature)
|
||||||
|
(d - Create a detached signature)"
|
||||||
|
'("n" "c" "d"))))
|
||||||
(helm-acase answer
|
(helm-acase answer
|
||||||
("n" 'normal)
|
("n" 'normal)
|
||||||
("c" 'clear)
|
("c" 'clear)
|
||||||
|
@ -159,7 +145,7 @@
|
||||||
(progn
|
(progn
|
||||||
(advice-add 'epa--select-keys :override #'helm-epa--select-keys)
|
(advice-add 'epa--select-keys :override #'helm-epa--select-keys)
|
||||||
(advice-add 'epa--read-signature-type :override #'helm-epa--read-signature-type))
|
(advice-add 'epa--read-signature-type :override #'helm-epa--read-signature-type))
|
||||||
(advice-remove 'epa--select-keys #'helm-epa--select-keys)
|
(advice-remove 'epa-select-keys #'helm-epa--select-keys)
|
||||||
(advice-remove 'epa--read-signature-type #'helm-epa--read-signature-type)))
|
(advice-remove 'epa--read-signature-type #'helm-epa--read-signature-type)))
|
||||||
|
|
||||||
(defun helm-epa-action-transformer (actions _candidate)
|
(defun helm-epa-action-transformer (actions _candidate)
|
|
@ -290,7 +290,7 @@ at point."
|
||||||
(delete-char -1) (setq del-dot t)
|
(delete-char -1) (setq del-dot t)
|
||||||
(setq helm-ec-target (substring helm-ec-target 0 (1- (length helm-ec-target)))))
|
(setq helm-ec-target (substring helm-ec-target 0 (1- (length helm-ec-target)))))
|
||||||
(cond ((eq first ?\()
|
(cond ((eq first ?\()
|
||||||
(helm-lisp-completion-at-point))
|
(helm-lisp-completion-or-file-name-at-point))
|
||||||
;; In eshell `pcomplete-parse-arguments' is called
|
;; In eshell `pcomplete-parse-arguments' is called
|
||||||
;; with `pcomplete-parse-arguments-function'
|
;; with `pcomplete-parse-arguments-function'
|
||||||
;; locally bound to `eshell-complete-parse-arguments'
|
;; locally bound to `eshell-complete-parse-arguments'
|
|
@ -23,8 +23,7 @@
|
||||||
(require 'edebug)
|
(require 'edebug)
|
||||||
|
|
||||||
(declare-function helm-lisp-completion-at-point "helm-elisp.el")
|
(declare-function helm-lisp-completion-at-point "helm-elisp.el")
|
||||||
(declare-function helm-elisp-show-doc-modeline "helm-elisp.el")
|
|
||||||
(defvar helm-elisp-help-function)
|
|
||||||
|
|
||||||
(defgroup helm-eval nil
|
(defgroup helm-eval nil
|
||||||
"Eval related Applications and libraries for Helm."
|
"Eval related Applications and libraries for Helm."
|
||||||
|
@ -84,13 +83,8 @@ Should take one arg: the string to display."
|
||||||
(define-key map (kbd "<left>") #'backward-char)
|
(define-key map (kbd "<left>") #'backward-char)
|
||||||
map))
|
map))
|
||||||
|
|
||||||
(defclass helm-evaluation-result-class (helm-source-dummy)
|
|
||||||
((echo-input-in-header-line
|
|
||||||
:initarg :echo-input-in-header-line
|
|
||||||
:initform 'never)))
|
|
||||||
|
|
||||||
(defun helm-build-evaluation-result-source ()
|
(defun helm-build-evaluation-result-source ()
|
||||||
(helm-make-source "Evaluation Result" 'helm-evaluation-result-class
|
(helm-build-dummy-source "Evaluation Result"
|
||||||
:multiline t
|
:multiline t
|
||||||
:mode-line "C-RET: nl-and-indent, M-tab: reindent, C-tab:complete, C-p/n: next/prec-line."
|
:mode-line "C-RET: nl-and-indent, M-tab: reindent, C-tab:complete, C-p/n: next/prec-line."
|
||||||
:filtered-candidate-transformer
|
:filtered-candidate-transformer
|
||||||
|
@ -98,11 +92,11 @@ Should take one arg: the string to display."
|
||||||
(list
|
(list
|
||||||
(condition-case nil
|
(condition-case nil
|
||||||
(with-helm-current-buffer
|
(with-helm-current-buffer
|
||||||
(pp-to-string
|
(pp-to-string
|
||||||
(if edebug-active
|
(if edebug-active
|
||||||
(edebug-eval-expression
|
(edebug-eval-expression
|
||||||
(read helm-pattern))
|
(read helm-pattern))
|
||||||
(eval (read helm-pattern) t))))
|
(eval (read helm-pattern) t))))
|
||||||
(error "Error"))))
|
(error "Error"))))
|
||||||
:nohighlight t
|
:nohighlight t
|
||||||
:keymap helm-eval-expression-map
|
:keymap helm-eval-expression-map
|
|
@ -67,24 +67,25 @@ If this variable is not set by the user, it will be calculated
|
||||||
automatically.")
|
automatically.")
|
||||||
|
|
||||||
(defun helm-external-commands-list-1 (&optional sort)
|
(defun helm-external-commands-list-1 (&optional sort)
|
||||||
"Return a list of all external commands the user can execute.
|
"Returns a list of all external commands the user can execute.
|
||||||
If `helm-external-commands-list' is non-nil it will return its
|
If `helm-external-commands-list' is non-nil it will return its
|
||||||
contents. Else it calculates all external commands and sets
|
contents. Else it calculates all external commands and sets
|
||||||
`helm-external-commands-list'."
|
`helm-external-commands-list'."
|
||||||
(or helm-external-commands-list
|
(helm-aif helm-external-commands-list
|
||||||
(setq helm-external-commands-list
|
it
|
||||||
(cl-loop for dir in (split-string (getenv "PATH") path-separator)
|
(setq helm-external-commands-list
|
||||||
when (and (file-exists-p dir)
|
(cl-loop
|
||||||
(file-accessible-directory-p dir))
|
for dir in (split-string (getenv "PATH") path-separator)
|
||||||
for lsdir = (cl-loop for i in (directory-files dir t)
|
when (and (file-exists-p dir) (file-accessible-directory-p dir))
|
||||||
for bn = (file-name-nondirectory i)
|
for lsdir = (cl-loop for i in (directory-files dir t)
|
||||||
when (and (not (member bn completions))
|
for bn = (file-name-nondirectory i)
|
||||||
(not (file-directory-p i))
|
when (and (not (member bn completions))
|
||||||
(file-executable-p i))
|
(not (file-directory-p i))
|
||||||
collect bn)
|
(file-executable-p i))
|
||||||
append lsdir into completions
|
collect bn)
|
||||||
finally return
|
append lsdir into completions
|
||||||
(if sort (sort completions 'string-lessp) completions)))))
|
finally return
|
||||||
|
(if sort (sort completions 'string-lessp) completions)))))
|
||||||
|
|
||||||
(defun helm-run-or-raise (exe &optional files detached)
|
(defun helm-run-or-raise (exe &optional files detached)
|
||||||
"Run asynchronously EXE or jump to the application window.
|
"Run asynchronously EXE or jump to the application window.
|
|
@ -132,11 +132,10 @@
|
||||||
(cl-assert (executable-find helm-fd-executable) nil "Could not find fd executable")
|
(cl-assert (executable-find helm-fd-executable) nil "Could not find fd executable")
|
||||||
(cl-assert (not (file-remote-p directory)) nil "Fd not supported on remote directories")
|
(cl-assert (not (file-remote-p directory)) nil "Fd not supported on remote directories")
|
||||||
(let ((default-directory directory))
|
(let ((default-directory directory))
|
||||||
(helm :sources (helm-make-source "Fd" 'helm-fd-class
|
(helm :sources (helm-make-source
|
||||||
:header-name
|
(format "fd (%s)"
|
||||||
(lambda (name)
|
(abbreviate-file-name default-directory))
|
||||||
(format "%s (%s)"
|
'helm-fd-class)
|
||||||
name (abbreviate-file-name default-directory))))
|
|
||||||
:buffer "*helm fd*")))
|
:buffer "*helm fd*")))
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -50,7 +50,6 @@ Using `setq' to modify this variable will have no effect."
|
||||||
(define-key map (kbd "a") 'helm-apropos)
|
(define-key map (kbd "a") 'helm-apropos)
|
||||||
(define-key map (kbd "e") 'helm-etags-select)
|
(define-key map (kbd "e") 'helm-etags-select)
|
||||||
(define-key map (kbd "l") 'helm-locate)
|
(define-key map (kbd "l") 'helm-locate)
|
||||||
(define-key map (kbd "L") 'helm-locate-library)
|
|
||||||
(define-key map (kbd "s") 'helm-surfraw)
|
(define-key map (kbd "s") 'helm-surfraw)
|
||||||
(define-key map (kbd "r") 'helm-regexp)
|
(define-key map (kbd "r") 'helm-regexp)
|
||||||
(define-key map (kbd "m") 'helm-man-woman)
|
(define-key map (kbd "m") 'helm-man-woman)
|
||||||
|
@ -85,7 +84,6 @@ Using `setq' to modify this variable will have no effect."
|
||||||
(define-key map (kbd "b") 'helm-resume)
|
(define-key map (kbd "b") 'helm-resume)
|
||||||
(define-key map (kbd "M-g i") 'helm-gid)
|
(define-key map (kbd "M-g i") 'helm-gid)
|
||||||
(define-key map (kbd "@") 'helm-packages)
|
(define-key map (kbd "@") 'helm-packages)
|
||||||
(define-key map (kbd "h p") 'helm-finder)
|
|
||||||
map)
|
map)
|
||||||
"Default keymap for \\[helm-command-prefix] commands.
|
"Default keymap for \\[helm-command-prefix] commands.
|
||||||
The normal global definition of the character \\[helm-command-prefix] indirects to this keymap.")
|
The normal global definition of the character \\[helm-command-prefix] indirects to this keymap.")
|
|
@ -533,16 +533,16 @@ Have no effect when grep backend use \"--color=\"."
|
||||||
(and rec-com rec-com-ack-p)))))))
|
(and rec-com rec-com-ack-p)))))))
|
||||||
|
|
||||||
(defun helm-grep--pipe-command-for-grep-command (smartcase pipe-switches &optional grep-cmd)
|
(defun helm-grep--pipe-command-for-grep-command (smartcase pipe-switches &optional grep-cmd)
|
||||||
(helm-acase (or grep-cmd (helm-grep-command))
|
(pcase (or grep-cmd (helm-grep-command))
|
||||||
;; Use grep for GNU regexp based tools.
|
;; Use grep for GNU regexp based tools.
|
||||||
(("grep" "zgrep" "git-grep")
|
((or "grep" "zgrep" "git-grep")
|
||||||
(format "grep --color=always%s %s"
|
(format "grep --color=always%s %s"
|
||||||
(if smartcase " -i" "")
|
(if smartcase " -i" "")
|
||||||
pipe-switches))
|
pipe-switches))
|
||||||
;; Use ack-grep for PCRE based tools.
|
;; Use ack-grep for PCRE based tools.
|
||||||
;; Sometimes ack-grep cmd is ack only so compare by matching ack.
|
;; Sometimes ack-grep cmd is ack only.
|
||||||
((guard (string-match-p "ack" it))
|
((and (pred (string-match-p "ack")) ack)
|
||||||
(format "%s --smart-case --color %s" it pipe-switches))))
|
(format "%s --smart-case --color %s" ack pipe-switches))))
|
||||||
|
|
||||||
(defun helm-grep--prepare-cmd-line (only-files &optional include zgrep)
|
(defun helm-grep--prepare-cmd-line (only-files &optional include zgrep)
|
||||||
(let* ((default-directory (or helm-ff-default-directory
|
(let* ((default-directory (or helm-ff-default-directory
|
||||||
|
@ -1196,7 +1196,7 @@ of grep."
|
||||||
:initform nil
|
:initform nil
|
||||||
:documentation
|
:documentation
|
||||||
" The grep backend that will be used.
|
" The grep backend that will be used.
|
||||||
It is currently used only as an internal flag
|
It is actually used only as an internal flag
|
||||||
and doesn't set the backend by itself.
|
and doesn't set the backend by itself.
|
||||||
You probably don't want to modify this.")
|
You probably don't want to modify this.")
|
||||||
(candidate-number-limit :initform 9999)
|
(candidate-number-limit :initform 9999)
|
||||||
|
@ -1243,7 +1243,7 @@ Argument DEFAULT-INPUT is use as `default' arg of `helm' and
|
||||||
INPUT is used as `input' arg of `helm'. See `helm' docstring.
|
INPUT is used as `input' arg of `helm'. See `helm' docstring.
|
||||||
|
|
||||||
Arg BACKEND when non-nil specifies which backend to use.
|
Arg BACKEND when non-nil specifies which backend to use.
|
||||||
It is used currently to specify \\='zgrep' or \\='git'.
|
It is used actually to specify \\='zgrep' or \\='git'.
|
||||||
When BACKEND \\='zgrep' is used don't prompt for a choice in
|
When BACKEND \\='zgrep' is used don't prompt for a choice in
|
||||||
recurse, and ignore EXTS, search being made recursively on files
|
recurse, and ignore EXTS, search being made recursively on files
|
||||||
matching `helm-zgrep-file-extension-regexp' only."
|
matching `helm-zgrep-file-extension-regexp' only."
|
||||||
|
@ -1635,12 +1635,8 @@ returns if available with current AG version."
|
||||||
(helm-default-directory)
|
(helm-default-directory)
|
||||||
default-directory))
|
default-directory))
|
||||||
(cmd-line (helm-grep-ag-prepare-cmd-line
|
(cmd-line (helm-grep-ag-prepare-cmd-line
|
||||||
;; NOTE Encode directory name and pattern,
|
helm-pattern (or (file-remote-p directory 'localname)
|
||||||
;; or it may not work with Chinese and maybe other non-utf8
|
directory)
|
||||||
;; characters on MSWindows systems issue#2677 and issue#2678.
|
|
||||||
(encode-coding-string helm-pattern locale-coding-system)
|
|
||||||
(or (file-remote-p directory 'localname)
|
|
||||||
(encode-coding-string directory locale-coding-system))
|
|
||||||
type))
|
type))
|
||||||
(start-time (float-time))
|
(start-time (float-time))
|
||||||
(proc-name (helm-grep--ag-command)))
|
(proc-name (helm-grep--ag-command)))
|
||||||
|
@ -1697,27 +1693,18 @@ returns if available with current AG version."
|
||||||
proc-name
|
proc-name
|
||||||
(replace-regexp-in-string "\n" "" event))))))))))
|
(replace-regexp-in-string "\n" "" event))))))))))
|
||||||
|
|
||||||
(defvar helm-grep-ag-map
|
|
||||||
(let ((map (make-sparse-keymap)))
|
|
||||||
(set-keymap-parent map helm-grep-map)
|
|
||||||
(define-key map (kbd "C-s") 'helm-grep-run-ag-grep-parent-directory)
|
|
||||||
map))
|
|
||||||
|
|
||||||
(defclass helm-grep-ag-class (helm-source-async)
|
(defclass helm-grep-ag-class (helm-source-async)
|
||||||
((nohighlight :initform t)
|
((nohighlight :initform t)
|
||||||
(pcre :initarg :pcre :initform t
|
(pcre :initarg :pcre :initform t
|
||||||
:documentation
|
:documentation
|
||||||
" Backend is using pcre regexp engine when non--nil.")
|
" Backend is using pcre regexp engine when non--nil.")
|
||||||
(keymap :initform 'helm-grep-ag-map)
|
(keymap :initform 'helm-grep-map)
|
||||||
(history :initform 'helm-grep-ag-history)
|
(history :initform 'helm-grep-ag-history)
|
||||||
(help-message :initform 'helm-grep-help-message)
|
(help-message :initform 'helm-grep-help-message)
|
||||||
(filtered-candidate-transformer :initform #'helm-grep-fc-transformer)
|
(filtered-candidate-transformer :initform #'helm-grep-fc-transformer)
|
||||||
(persistent-action :initform 'helm-grep-persistent-action)
|
(persistent-action :initform 'helm-grep-persistent-action)
|
||||||
(persistent-help :initform "Jump to line (`C-u' Record in mark ring)")
|
(persistent-help :initform "Jump to line (`C-u' Record in mark ring)")
|
||||||
(candidate-number-limit :initform 99999)
|
(candidate-number-limit :initform 99999)
|
||||||
(directory :initarg :directory :initform nil
|
|
||||||
:documentation
|
|
||||||
" Directory currently searched.")
|
|
||||||
(requires-pattern :initform 2)
|
(requires-pattern :initform 2)
|
||||||
(nomark :initform t)
|
(nomark :initform t)
|
||||||
(action :initform 'helm-grep-actions)
|
(action :initform 'helm-grep-actions)
|
||||||
|
@ -1741,30 +1728,16 @@ If INPUT is provided, use it as the search string."
|
||||||
:header-name (lambda (name)
|
:header-name (lambda (name)
|
||||||
(format "%s [%s]"
|
(format "%s [%s]"
|
||||||
name (abbreviate-file-name directory)))
|
name (abbreviate-file-name directory)))
|
||||||
:directory directory
|
|
||||||
:action (append helm-grep-actions
|
|
||||||
`((,(format "%s grep parent directory"
|
|
||||||
(upcase (helm-grep--ag-command)))
|
|
||||||
. helm-grep-ag-grep-parent-directory)))
|
|
||||||
:candidates-process
|
:candidates-process
|
||||||
(lambda () (helm-grep-ag-init directory type))))
|
(lambda () (helm-grep-ag-init directory type))))
|
||||||
(helm-set-local-variable 'helm-input-idle-delay helm-grep-input-idle-delay)
|
(helm-set-local-variable 'helm-input-idle-delay helm-grep-input-idle-delay)
|
||||||
(helm :sources 'helm-source-grep-ag
|
(helm :sources 'helm-source-grep-ag
|
||||||
|
:keymap helm-grep-map
|
||||||
:history 'helm-grep-ag-history
|
:history 'helm-grep-ag-history
|
||||||
:input input
|
:input input
|
||||||
:truncate-lines helm-grep-truncate-lines
|
:truncate-lines helm-grep-truncate-lines
|
||||||
:buffer (format "*helm %s*" (helm-grep--ag-command))))
|
:buffer (format "*helm %s*" (helm-grep--ag-command))))
|
||||||
|
|
||||||
(defun helm-grep-ag-grep-parent-directory (_candidate)
|
|
||||||
"Restart helm-grep-ag in the parent of the currently searched directory."
|
|
||||||
(let* ((src (with-helm-buffer (car helm-sources)))
|
|
||||||
(directory (helm-basedir (helm-get-attr 'directory src) t))
|
|
||||||
(input helm-pattern))
|
|
||||||
(helm-grep-ag-1 directory nil input)))
|
|
||||||
|
|
||||||
(helm-make-command-from-action helm-grep-run-ag-grep-parent-directory
|
|
||||||
"Ag grep parent directory." 'helm-grep-ag-grep-parent-directory)
|
|
||||||
|
|
||||||
(defun helm-grep-ag (directory with-types)
|
(defun helm-grep-ag (directory with-types)
|
||||||
"Start grep AG in DIRECTORY.
|
"Start grep AG in DIRECTORY.
|
||||||
When WITH-TYPES is non-nil provide completion on AG types."
|
When WITH-TYPES is non-nil provide completion on AG types."
|
|
@ -588,10 +588,10 @@ On completion (\\[helm-ff-run-complete-fn-at-point]):
|
||||||
|
|
||||||
Use of wildcard is supported to run an action over a set of files.
|
Use of wildcard is supported to run an action over a set of files.
|
||||||
|
|
||||||
Example: You can copy all the files with \".el\" extension by using \"*.el\" and
|
Example: You can copy all the files with \".el\" extension by using \"*.el\" and
|
||||||
then run copy action.
|
then run copy action.
|
||||||
|
|
||||||
Similarly, \"**.el\" (note the two stars) will recursively select all \".el\"
|
Similarly, \"**.el\" (note the two stars) will recursively select all \".el\"
|
||||||
files under the current directory.
|
files under the current directory.
|
||||||
|
|
||||||
Note that when recursively copying files, you may have files with same name
|
Note that when recursively copying files, you may have files with same name
|
||||||
|
@ -606,7 +606,7 @@ to backup files in current directory.
|
||||||
This command is available only when `dired-async-mode' is active.
|
This command is available only when `dired-async-mode' is active.
|
||||||
|
|
||||||
When using an action that involves an external backend (e.g. grep), using \"**\"
|
When using an action that involves an external backend (e.g. grep), using \"**\"
|
||||||
is not recommended (even though it works fine) because it will be slower to
|
is not recommended (even thought it works fine) because it will be slower to
|
||||||
select all the files. You are better off leaving the backend to do it, it will
|
select all the files. You are better off leaving the backend to do it, it will
|
||||||
be faster. However, if you know you have not many files it is reasonable to use
|
be faster. However, if you know you have not many files it is reasonable to use
|
||||||
this, also using not recursive wildcard (e.g. \"*.el\") is perfectly fine for
|
this, also using not recursive wildcard (e.g. \"*.el\") is perfectly fine for
|
||||||
|
@ -614,14 +614,14 @@ this.
|
||||||
|
|
||||||
The \"**\" feature is active by default in the option `helm-file-globstar'. It
|
The \"**\" feature is active by default in the option `helm-file-globstar'. It
|
||||||
is different from the Bash \"shopt globstar\" feature in that to list files with
|
is different from the Bash \"shopt globstar\" feature in that to list files with
|
||||||
a named extension recursively you would write \"**.el\" whereas in Bash it would
|
a named extension recursively you would write \"**.el\" whereas in Bash it would
|
||||||
be \"**/*.el\". Directory selection with \"**/\" like Bash \"shopt globstar\"
|
be \"**/*.el\". Directory selection with \"**/\" like Bash \"shopt globstar\"
|
||||||
option is not supported yet.
|
option is not supported yet.
|
||||||
|
|
||||||
Helm supports different styles of wildcards:
|
Helm supports different styles of wildcards:
|
||||||
|
|
||||||
- `sh' style, the ones supported by `file-expand-wildcards'.
|
- `sh' style, the ones supported by `file-expand-wildcards'.
|
||||||
e.g. \"*.el\", \"*.[ch]\" which match respectively all \".el\"
|
e.g. \"*.el\", \"*.[ch]\" which match respectively all \".el\"
|
||||||
files or all \".c\" and \".h\" files.
|
files or all \".c\" and \".h\" files.
|
||||||
|
|
||||||
- `bash' style (partially) In addition to what allowed in `sh'
|
- `bash' style (partially) In addition to what allowed in `sh'
|
||||||
|
@ -807,7 +807,7 @@ instead its scp method if you want to avoid out of memory
|
||||||
problems and crash Emacs or the whole system. Moreover when using
|
problems and crash Emacs or the whole system. Moreover when using
|
||||||
scp method, you will hit a bug when copying more than 3 files at
|
scp method, you will hit a bug when copying more than 3 files at
|
||||||
the time, see [[https://github.com/emacs-helm/helm/issues/1945][bug#1945]].
|
the time, see [[https://github.com/emacs-helm/helm/issues/1945][bug#1945]].
|
||||||
The best way currently is using Rsync to copy files from or to
|
The best way actually is using Rsync to copy files from or to
|
||||||
remote, see [[Use Rsync to copy files][Use Rsync to copy files]].
|
remote, see [[Use Rsync to copy files][Use Rsync to copy files]].
|
||||||
Also if you often work on remote you may consider using SSHFS
|
Also if you often work on remote you may consider using SSHFS
|
||||||
instead of relying on tramp.
|
instead of relying on tramp.
|
||||||
|
@ -873,7 +873,7 @@ rsync command line with a prefix arg (see above).
|
||||||
|
|
||||||
Since Android doesn't provide anymore mass storage for USB, it is
|
Since Android doesn't provide anymore mass storage for USB, it is
|
||||||
not simple to access files on Android, the best way to do this
|
not simple to access files on Android, the best way to do this
|
||||||
currently seems to use Adb, here some hints to set this up, read
|
actually seems to use Adb, here some hints to set this up, read
|
||||||
in addition the Tramp documentation.
|
in addition the Tramp documentation.
|
||||||
|
|
||||||
1) Install Adb, most distribution provide it.
|
1) Install Adb, most distribution provide it.
|
||||||
|
@ -915,40 +915,6 @@ On remote files grep is not well supported by TRAMP unless you suspend updates b
|
||||||
entering the pattern and re-enable it once your pattern is ready.
|
entering the pattern and re-enable it once your pattern is ready.
|
||||||
To toggle suspend-update, use `\\<helm-map>\\[helm-toggle-suspend-update]'.
|
To toggle suspend-update, use `\\<helm-map>\\[helm-toggle-suspend-update]'.
|
||||||
|
|
||||||
*** Compressing or uncompressing files from helm-find-files
|
|
||||||
|
|
||||||
**** Compressing/uncompressing using Helm commands
|
|
||||||
|
|
||||||
Helm provide commands like dired (reusing dired code)
|
|
||||||
to (un)compress files from `helm-find-files', however these
|
|
||||||
commands are asynchronous.
|
|
||||||
|
|
||||||
You can use `\\<helm-find-files-map>\\[helm-ff-run-compress-marked-files]' to compress marked files.
|
|
||||||
To compress file(s) to an archive use `\\<helm-find-files-map>\\[helm-ff-run-compress-to]'.
|
|
||||||
|
|
||||||
To quickly compress/uncompress small files without quitting Helm use `\\<helm-find-files-map>\\[helm-ff-persistent-compress]'.
|
|
||||||
NOTE: This persistent action is NOT asynchronous, IOW it will block Helm
|
|
||||||
for a while until compression/uncompression finish.
|
|
||||||
|
|
||||||
**** Compressing/uncompressing using external commands in Eshell
|
|
||||||
|
|
||||||
You can use Eshell aliases to uncompress files,
|
|
||||||
see [[Execute Eshell commands on files][Execute Eshell commands on files]] for more infos.
|
|
||||||
|
|
||||||
Here some aliases using commands from the excellent =atools= package:
|
|
||||||
|
|
||||||
alias pack2zip apack -e -F .zip $* &
|
|
||||||
alias pack2gz apack -e -F .tar.gz $* &
|
|
||||||
alias pack2bz apack -e -F .tar.bz $* &
|
|
||||||
alias pack2xz apack -e -F .tar.xz $* &
|
|
||||||
alias unpack aunpack $1 &
|
|
||||||
|
|
||||||
Note the \"&\" at end of commands that make eshell aliases asynchronous.
|
|
||||||
NOTE: Using the ampersand at end of command to make it asynchronous is broken
|
|
||||||
in all emacs versions before emacs-28 (see emacs bug#50209).
|
|
||||||
|
|
||||||
Of course you can use any other commands of your choice as aliases.
|
|
||||||
|
|
||||||
*** Execute Eshell commands on files
|
*** Execute Eshell commands on files
|
||||||
|
|
||||||
Setting up aliases in Eshell allows you to set up powerful customized commands.
|
Setting up aliases in Eshell allows you to set up powerful customized commands.
|
||||||
|
@ -1040,9 +1006,9 @@ Starting at helm version 2.9.7 it is somewhat possible to
|
||||||
colorize fnames by listing files without loosing performances with
|
colorize fnames by listing files without loosing performances with
|
||||||
external commands (ls and awk) if your system is compatible.
|
external commands (ls and awk) if your system is compatible.
|
||||||
For this you can use `helm-list-dir-external' as value
|
For this you can use `helm-list-dir-external' as value
|
||||||
for `helm-list-remote-directory-fn'.
|
for `helm-list-directory-function'.
|
||||||
|
|
||||||
See `helm-list-remote-directory-fn' documentation for more infos.
|
See `helm-list-directory-function' documentation for more infos.
|
||||||
|
|
||||||
**** Completing host
|
**** Completing host
|
||||||
|
|
||||||
|
@ -1301,10 +1267,7 @@ If `all-the-icons' package is installed, turning on
|
||||||
|\\[helm-ff-sort-by-size]|Sort by size.
|
|\\[helm-ff-sort-by-size]|Sort by size.
|
||||||
|\\[helm-ff-toggle-dirs-only]|Show only directories.
|
|\\[helm-ff-toggle-dirs-only]|Show only directories.
|
||||||
|\\[helm-ff-toggle-files-only]|Show only files.
|
|\\[helm-ff-toggle-files-only]|Show only files.
|
||||||
|\\[helm-ff-sort-by-ext]|Sort by extensions.
|
|\\[helm-ff-sort-by-ext]|Sort by extensions.")
|
||||||
|\\[helm-ff-run-compress-to]|Compress file(s) to archive.
|
|
||||||
|\\[helm-ff-run-compress-marked-files]|Compress file(s).
|
|
||||||
|\\[helm-ff-persistent-compress]|Compress file(s) without quitting.")
|
|
||||||
|
|
||||||
;;; Help for file-name-history
|
;;; Help for file-name-history
|
||||||
;;
|
;;
|
||||||
|
@ -2288,15 +2251,6 @@ See [[Moving in `helm-buffer'][Moving in `helm-buffer']].
|
||||||
(defvar helm-top-help-message
|
(defvar helm-top-help-message
|
||||||
"* Helm Top
|
"* Helm Top
|
||||||
|
|
||||||
** Tips
|
|
||||||
|
|
||||||
*** Auto update
|
|
||||||
|
|
||||||
You can enable auto updating in `helm-top' by turning on
|
|
||||||
`helm-top-poll-mode' either interactively or in your init file
|
|
||||||
with (helm-top-poll-mode 1).
|
|
||||||
Calling `helm-top' with a prefix arg also toggle auto updating.
|
|
||||||
|
|
||||||
** Commands
|
** Commands
|
||||||
\\<helm-top-map>
|
\\<helm-top-map>
|
||||||
|Keys|Description
|
|Keys|Description
|
|
@ -100,7 +100,7 @@ Don't use `setq' to set this."
|
||||||
:group 'helm-imenu
|
:group 'helm-imenu
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:set (lambda (var val)
|
:set (lambda (var val)
|
||||||
(if (require 'all-the-icons nil t)
|
(if (featurep 'all-the-icons)
|
||||||
(set var val)
|
(set var val)
|
||||||
(set var nil))))
|
(set var nil))))
|
||||||
|
|
||||||
|
@ -111,17 +111,17 @@ Don't use `setq' to set this."
|
||||||
:group 'helm-imenu
|
:group 'helm-imenu
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:set (lambda (var val)
|
:set (lambda (var val)
|
||||||
(if (require 'all-the-icons nil t)
|
(if (featurep 'all-the-icons)
|
||||||
(set var val)
|
(set var val)
|
||||||
(set var nil))))
|
(set var nil))))
|
||||||
|
|
||||||
(defcustom helm-imenu-icon-type-alist
|
(defcustom helm-imenu-icon-type-alist
|
||||||
'(("Array" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
'(("Array" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
||||||
("Arrays" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
("Array" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
||||||
|
("Boolean" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
||||||
("Boolean" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
("Boolean" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
||||||
("Booleans" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
|
||||||
("Class" . (all-the-icons-octicon "package" :face font-lock-type-face))
|
("Class" . (all-the-icons-octicon "package" :face font-lock-type-face))
|
||||||
("Classes" . (all-the-icons-octicon "package" :face font-lock-type-face))
|
("Class" . (all-the-icons-octicon "package" :face font-lock-type-face))
|
||||||
("Color" . (all-the-icons-material "color_lens" :face font-lock-builtin-face))
|
("Color" . (all-the-icons-material "color_lens" :face font-lock-builtin-face))
|
||||||
("Colors" . (all-the-icons-material "color_lens" :face font-lock-builtin-face))
|
("Colors" . (all-the-icons-material "color_lens" :face font-lock-builtin-face))
|
||||||
("Constant" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
("Constant" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
||||||
|
@ -157,7 +157,7 @@ Don't use `setq' to set this."
|
||||||
("Module" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
|
("Module" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
|
||||||
("Modules" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
|
("Modules" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
|
||||||
("Numeric" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
("Numeric" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
||||||
("Numerics" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
("Numeric" . (all-the-icons-material "crop" :face font-lock-builtin-face))
|
||||||
("Object" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
|
("Object" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
|
||||||
("Objects" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
|
("Objects" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
|
||||||
("Operator" . (all-the-icons-faicon "calculator" :face font-lock-builtin-face))
|
("Operator" . (all-the-icons-faicon "calculator" :face font-lock-builtin-face))
|
||||||
|
@ -167,7 +167,7 @@ Don't use `setq' to set this."
|
||||||
("Reference" . (all-the-icons-octicon "book" :face font-lock-variable-name-face))
|
("Reference" . (all-the-icons-octicon "book" :face font-lock-variable-name-face))
|
||||||
("References" . (all-the-icons-octicon "book" :face font-lock-variable-name-face))
|
("References" . (all-the-icons-octicon "book" :face font-lock-variable-name-face))
|
||||||
("Snippet" . (all-the-icons-material "border_style" :face font-lock-variable-name-face))
|
("Snippet" . (all-the-icons-material "border_style" :face font-lock-variable-name-face))
|
||||||
("Snippets" . (all-the-icons-material "border_style" :face font-lock-variable-name-face))
|
("Snippet" . (all-the-icons-material "border_style" :face font-lock-variable-name-face))
|
||||||
("String" . (all-the-icons-material "text_fields" :face font-lock-variable-name-face))
|
("String" . (all-the-icons-material "text_fields" :face font-lock-variable-name-face))
|
||||||
("Strings" . (all-the-icons-material "text_fields" :face font-lock-variable-name-face))
|
("Strings" . (all-the-icons-material "text_fields" :face font-lock-variable-name-face))
|
||||||
("Struct" . (all-the-icons-faicon "cog" :face font-lock-type-face))
|
("Struct" . (all-the-icons-faicon "cog" :face font-lock-type-face))
|
||||||
|
@ -320,8 +320,7 @@ The sexp should be an `all-the-icons' function with its args."
|
||||||
(if (equal (cdr cur) mb)
|
(if (equal (cdr cur) mb)
|
||||||
(prog1 nil
|
(prog1 nil
|
||||||
(helm-set-pattern "")
|
(helm-set-pattern "")
|
||||||
(helm-force-update
|
(helm-force-update (concat "\\_<" (car cur) "\\_>")))
|
||||||
(concat "\\_<" (regexp-quote (car cur)) "\\_>")))
|
|
||||||
t)))
|
t)))
|
||||||
|
|
||||||
(defun helm-imenu-quit-and-find-file-fn (source)
|
(defun helm-imenu-quit-and-find-file-fn (source)
|
||||||
|
@ -407,11 +406,12 @@ The sexp should be an `all-the-icons' function with its args."
|
||||||
(and (cdr elm)
|
(and (cdr elm)
|
||||||
;; Semantic uses overlays whereas imenu uses
|
;; Semantic uses overlays whereas imenu uses
|
||||||
;; markers (Bug#1706).
|
;; markers (Bug#1706).
|
||||||
(setcdr elm (helm-acase (cdr elm) ; Same as [1].
|
(setcdr elm (pcase (cdr elm) ; Same as [1].
|
||||||
((guard (overlayp it))
|
((and ov (pred overlayp))
|
||||||
(copy-overlay it))
|
(copy-overlay ov))
|
||||||
((guard (or (markerp it) (integerp it)))
|
((and mk (or (pred markerp)
|
||||||
(copy-marker it))))
|
(pred integerp)))
|
||||||
|
(copy-marker mk))))
|
||||||
(list elm))))))
|
(list elm))))))
|
||||||
|
|
||||||
(defun helm-imenu--get-prop (item)
|
(defun helm-imenu--get-prop (item)
|
||||||
|
@ -443,9 +443,10 @@ The icon is found in `helm-imenu-icon-type-alist', if not
|
||||||
(cl-loop for (k . v) in candidates
|
(cl-loop for (k . v) in candidates
|
||||||
;; (k . v) == (symbol-name . marker)
|
;; (k . v) == (symbol-name . marker)
|
||||||
for bufname = (buffer-name
|
for bufname = (buffer-name
|
||||||
(helm-acase v
|
(pcase v
|
||||||
((guard (overlayp it)) (overlay-buffer it))
|
((pred overlayp) (overlay-buffer v))
|
||||||
((guard (markerp it)) (marker-buffer it))))
|
((or (pred markerp) (pred integerp))
|
||||||
|
(marker-buffer v))))
|
||||||
for types = (or (helm-imenu--get-prop k)
|
for types = (or (helm-imenu--get-prop k)
|
||||||
(list (if (with-current-buffer bufname
|
(list (if (with-current-buffer bufname
|
||||||
(derived-mode-p 'prog-mode))
|
(derived-mode-p 'prog-mode))
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue