From 7e7acac761c1b1304f94dfb5a3b6bed1659c73a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wo=C5=BAniak?= Date: Sat, 29 Aug 2020 14:43:11 +0200 Subject: [PATCH] Added emacs --- .emacs.d/awesome-tab.el | 1924 ++++++++++++++++++++++++++++++++++++++ .emacs.d/emacs-custom.el | 14 + .emacs.d/emacs-livedown | 1 + .emacs.d/init.el | 192 ++++ 4 files changed, 2131 insertions(+) create mode 100644 .emacs.d/awesome-tab.el create mode 100644 .emacs.d/emacs-custom.el create mode 160000 .emacs.d/emacs-livedown create mode 100644 .emacs.d/init.el diff --git a/.emacs.d/awesome-tab.el b/.emacs.d/awesome-tab.el new file mode 100644 index 0000000..bb1ab42 --- /dev/null +++ b/.emacs.d/awesome-tab.el @@ -0,0 +1,1924 @@ +;;; awesome-tab.el --- Provide an out of box configuration to use tab in Emacs. + +;; Filename: awesome-tab.el +;; Description: Provide an out of box configuration to use awesome-tab in Emacs. +;; Author: Andy Stewart +;; Maintainer: Andy Stewart +;; Copyright (C) 2018, Andy Stewart, all rights reserved. +;; Created: 2018-09-17 22:14:34 +;; Version: 7.3 +;; Last-Updated: 2020-04-10 12:36:52 +;; By: Andy Stewart +;; URL: http://www.emacswiki.org/emacs/download/awesome-tab.el +;; Keywords: +;; Compatibility: GNU Emacs 27.0.50 +;; +;; Features that might be required by this library: +;; +;; `cl-lib' `color' `which-func' +;; + +;;; This file is NOT part of GNU Emacs + +;;; License +;; +;; 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, 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: +;; +;; Provide an out of box configuration to use tab in Emacs. +;; + +;;; Installation: +;; +;; Put awesome-tab.el to your load-path. +;; The load-path is usually ~/elisp/. +;; It's set in your ~/.emacs like this: +;; (add-to-list 'load-path (expand-file-name "~/elisp")) +;; +;; And the following to your ~/.emacs startup file. +;; +;; (require 'awesome-tab) +;; (awesome-tab-mode t) +;; +;; No need more. +;; +;; You can use below commands for you need: +;; +;; `awesome-tab-switch-group' +;; `awesome-tab-select-beg-tab' +;; `awesome-tab-select-end-tab' +;; `awesome-tab-forward-tab-other-window' +;; `awesome-tab-backward-tab-other-window' +;; `awesome-tab-kill-other-buffers-in-current-group' +;; `awesome-tab-kill-all-buffers-in-current-group' +;; `awesome-tab-kill-match-buffers-in-current-group' +;; `awesome-tab-keep-match-buffers-in-current-group' +;; `awesome-tab-move-current-tab-to-left' +;; `awesome-tab-move-current-tab-to-right' +;; +;; If you're helm fans, you need add below code in your helm config: +;; +;; (awesome-tab-build-helm-source) +;; + +;;; Customize: +;; +;; `awesome-tab-cycle-scope' +;; `awesome-tab-label-fixed-length' +;; `awesome-tab-auto-scroll-flag' +;; `awesome-tab-common-group-name' +;; `awesometab-hide-tabs-hooks' +;; `awesome-tab-height' +;; `awesome-tab-display-sticky-function-name' +;; `awesome-tab-display-icon' +;; `awesome-tab-show-tab-index' +;; + +;;; Change log: +;; +;; 2020/04/10 +;; * Fix issue #81 +;; +;; 2020/03/22 +;; * Support EAF mode. +;; * Add options for customize active bar. +;; +;; 2020/03/21 +;; * Remove unnecessary tab style and include active bar. +;; +;; 2020/02/13 +;; * Add `awesome-tab-all-the-icons-is-load-p' option. +;; * Fix window-live-p error when click tab. +;; +;; 2020/01/13 +;; * Add new option `awesome-tab-label-max-length'. +;; +;; 2019/12/22 +;; * Add flycheck temp buffer in hide black list. +;; +;; 2019/10/10 +;; * Fix issue #58 click tab select window of tab first. +;; +;; 2019/09/12 +;; * Fix top-line above tab issue. +;; +;; 2019/08/13 +;; * Add new option `awesome-tab-height'. +;; +;; 2019/08/03 +;; * Adjust default value of `awesome-tab-ace-quit-keys'. +;; +;; 2019/08/02 +;; * Refactroy `awesome-tab-ace-jump'. +;; * Refactory variable name. +;; * Remove `awesome-tab-adjust-buffer-order' since `awesome-tab-ace-jump' is enough. +;; +;; 2019/08/01 +;; * Quit when user press Ctrl + g. +;; * Make ace string use foreground same as `font-lock-function-name-face'. +;; * Remove `awesome-tab-prefix-map' +;; +;; 2019/07/18 +;; * Use ema2159's way to render icon. +;; +;; 2019/07/17 +;; * Init `header-line' height from `default' face, +;; `header-line' default inhibit from `mode-line', +;; awesome-tab icon will disappear if `mode-line' height set with 0.1 by other plugins (such as awesome-tray). +;; * Use `stringp' instead `ignore-errors' in `awesome-tab-icon-for-tab'. +;; +;; 2019/07/15 +;; * Don't call `awesome-tab-adjust-buffer-order' if user use mouse click tab. +;; +;; 2019/07/01 +;; * Make awesome-tab's colors change with user selected theme, thank you so much AmaiKinono. +;; * Adjust dark mode background tab's color. +;; * Remove local-mode code. +;; * Refactory code. +;; +;; 2019/06/30 +;; * Add customize option `awesome-tab-display-icon' . +;; +;; 2019/06/28 +;; * Fix messages buffer icon an FontAwesome errors, thanks ema2159. ;) +;; * Set height of tab face, avoid tab render error when user don't load any third theme. +;; * Make `header-line' background same as default face. +;; +;; 2019/06/26 +;; * Fix error of void function awesome-tab-separator-separator-height +;; +;; 2019/06/25 +;; * Still display tab if all-the-icons cause "Error during redisplay" error in MacOS. +;; +;; 2019/06/24 +;; * Use ema2159's patch to fix icon face performance. +;; +;; 2019/06/23 +;; * Render file icon in tab when `all-the-icons' is load. +;; * Use `all-the-icons-icon-for-buffer' to display icon for dired mode. +;; * Support color icon. +;; * Don't customize background of tab, use `default' face's background as tab background. +;; +;; 2019/04/14 +;; * Make `awesome-tab-last-sticky-func-name' default with nil. +;; +;; 2019/03/21 +;; * Make `awesome-tab-last-sticky-func-name' as buffer variable. +;; +;; 2019/03/19 +;; * If `tab-index' more than length of visible tabs, selet the last tab. +;; +;; 2019/03/18 +;; * Add new command `awesome-tab-select-visible-tab'. +;; +;; 2019/03/16 +;; * Fix integerp error. +;; +;; 2019/03/14 +;; * Try to fix numberp error. +;; +;; 2019/03/12 +;; * Display sticky function name in tab. +;; +;; 2019/03/09 +;; * Absorb powerline code, keep single file. +;; * Remove some separator face that not suitable for displaying tab. +;; * Add option `awesome-tab-style'. +;; +;; 2019/03/07 +;; * Add `cl' dependence. +;; +;; 2019/03/03 +;; * Automatically adsorb tabs after switching tabs, making switch tabs quickly. +;; * Fix many typo errors. +;; * Add `awesome-tab-adjust-buffer-order-function'. +;; * Don't trigger by awesome-tab command, it's annoying. +;; +;; 2019/02/23 +;; * Significantly optimize the performance of switching tab by avoiding excessive calls `project-current'. +;; * Use `powerline' render tab, it's beautiful!!! +;; +;; 2018/12/27 +;; * Tab will hide if ```awesome-tab-hide-tab-function``` return t, you can write your own code to customize hide rules. +;; +;; 2018/11/16 +;; * Open new tab on right of current one. +;; +;; 2018/11/14 +;; * Remove wheel features, emacser should only use the keyboard to operate Emacs. +;; +;; 2018/11/01 +;; * Remove `projectile' depend. +;; +;; 2018/10/29 +;; * Add `mwheel' depend. +;; +;; 2018/09/29 +;; * Add new command `awesome-tab-kill-other-buffers-in-current-group' +;; * Not enable mode default. +;; +;; 2018/09/25 +;; * Adjust magit regexp to only match magit buffer, not file that named with magit. +;; +;; 2018/09/22 +;; * Adjust `awesome-tab-buffer-list' to hide unused buffer to user. +;; +;; 2018/09/20 +;; * Remove empty header line from magit buffers. +;; * Add new function `awesome-tab-kill-match-buffers-in-current-group', it's handy in mixin mode, such as web-mode. +;; * Add new function `awesome-tab-keep-match-buffers-in-current-group', it's handy in mixin mode, such as web-mode. +;; * Fix error cause by `awesome-tab-kill-buffer-match-rule'. +;; +;; 2018/09/18 +;; * Fix unselect tab height and add option `awesome-tab-hide-tab-rules' +;; * Use `awesome-tab-groups-hash' store every buffer's project name avoid performance issue cause by `projectile-project-name'. +;; +;; 2018/09/17 +;; * First released. +;; + +;;; Acknowledgements: +;; +;; casouri: documentation and many useful patches. +;; AmaiKinono: contributed to the patch that make tab color change with the theme automatically +;; + +;;; TODO +;; +;; +;; + +;;; Require +(require 'cl-lib) +(require 'color) + +;;; Code: +;;;;;;;;;;;;;;;;;;;;;;; Awesome-Tab source code ;;;;;;;;;;;;;;;;;;;;;;; + +(defgroup awesome-tab nil + "Display a tab bar in the header line." + :group 'convenience) + +(defcustom awesome-tab-cycle-scope nil + "*Specify the scope of cyclic navigation through tabs. +The following scopes are possible: + +- `tabs' + Navigate through visible tabs only. +- `groups' + Navigate through tab groups only. +- default + Navigate through visible tabs, then through tab groups." + :group 'awesome-tab + :type '(choice :tag "Cycle through..." + (const :tag "Visible Tabs Only" tabs) + (const :tag "Tab Groups Only" groups) + (const :tag "Visible Tabs then Tab Groups" nil))) + +(defcustom awesome-tab-auto-scroll-flag t + "*Non-nil means to automatically scroll the tab bar. +That is, when a tab is selected outside of the tab bar visible area, +the tab bar is scrolled horizontally so the selected tab becomes +visible." + :group 'awesome-tab + :type 'boolean) + +(defcustom awesome-tab-common-group-name "Common" + "If the current buffer does not belong to any project, +the group name uses the name of this variable." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-label-fixed-length 0 + "Fixed length of label. Set to 0 if dynamic." + :group 'awesome-tab + :type 'int) + +(defcustom awesome-tab-label-max-length 30 + "Max length of label. Set to 0 if dynamic." + :group 'awesome-tab + :type 'int) + +(defcustom awesometab-hide-tabs-hooks + '(magit-status-mode-hook magit-popup-mode-hook reb-mode-hook) + "Some buffer's header line is empty that make its window insufficient of space to display all content. +Feel free to add hook in this option. ;)" + :type '(repeat symbol) + :group 'awesome-tab) + +(defcustom awesome-tab-display-sticky-function-name nil + "Non-nil to display sticky function name in tab. +Sticky function is the function at the top of the current window sticky." + :group 'awesome-tab + :type 'boolean) + +(defcustom awesome-tab-display-icon t + "Non-nil to display icon in tab, this feature need `all-the-icons' is loaded. +Set this option with nil if you don't like icon in tab." + :group 'awesome-tab + :type 'boolean) + +(defcustom awesome-tab-ace-keys '(?j ?k ?l ?s ?d ?f) + "Keys used for `awesome-tab-ace-jump'." + :group 'awesome-tab + :set #'(lambda (symbol value) + (set-default symbol value) + (let ((1k-seqs nil) + (2k-seqs nil)) + (dolist (a value) + (dolist (b value) + (push (list a b) 2k-seqs)) + (push (list a) 1k-seqs)) + (setq awesome-tab-ace-2-key-seqs (nreverse 2k-seqs)) + (setq awesome-tab-ace-1-key-seqs (nreverse 1k-seqs)))) + :type '(repeat :tag "Keys" character)) + +(defcustom awesome-tab-ace-quit-keys '(?\C-g ?q ?\s) + "Keys used to quit from ace jumping." + :group 'awesome-tab + :type '(repeat :tag "Keys" character)) + +(defcustom awesome-tab-ace-str-style 'replace-icon + "Position of ace strings." + :group 'awesome-tab + :type '(choice + (const :tag "Replace icon" replace-icon) + (const :tag "Left" left) + (const :tag "Right" right))) + +(defcustom awesome-tab-height 190 + "The height of tab face." + :group 'awesome-tab + :type 'int) + +(defcustom awesome-tab-icon-v-adjust 0 + "The v-adjust of tab icon." + :group 'awesome-tab + :type 'float) + +(defcustom awesome-tab-icon-height 0.6 + "The height of icon. +It will render top-line on tab when you set this variable bigger than 0.9." + :group 'awesome-tab + :type 'float) + +(defcustom awesome-tab-show-tab-index nil + "Non-nil to display index in tab." + :group 'awesome-tab + :type 'boolean) + +(defcustom awesome-tab-index-format-str "[%d] " + "Format string for tab index." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-dark-selected-foreground-color nil + "Foreground for selected tab in dark theme." + :group 'awesome-tab + :type '(choice (const nil) string)) + +(defcustom awesome-tab-dark-unselected-foreground-color nil + "Foreground for unselected tab in dark theme." + :group 'awesome-tab + :type '(choice (const nil) string)) + +(defcustom awesome-tab-light-selected-foreground-color nil + "Foreground for selected tab in light theme." + :group 'awesome-tab + :type '(choice (const nil) string)) + +(defcustom awesome-tab-light-unselected-foreground-color nil + "Foreground for unselected tab in light theme." + :group 'awesome-tab + :type '(choice (const nil) string)) + +(defcustom awesome-tab-terminal-dark-select-background-color "#222222" + "Select background color for terminal dark mode." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-terminal-dark-select-foreground-color "#AAAAAA" + "Select foreground color for terminal dark mode." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-terminal-dark-unselect-background-color "#000000" + "Unselect background color for terminal dark mode." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-terminal-dark-unselect-foreground-color "#AAAAAA" + "Unselect foreground color for terminal dark mode." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-terminal-light-select-background-color "#AAAAAA" + "Select background color for terminal light mode." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-terminal-light-select-foreground-color "#333333" + "Select foreground color for terminal light mode." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-terminal-light-unselect-background-color "#333333" + "Unselect background color for terminal light mode." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-terminal-light-unselect-foreground-color "#AAAAAA" + "Unselect foreground color for terminal light mode." + :group 'awesome-tab + :type 'string) + +(defcustom awesome-tab-dark-active-bar-color nil + "The bar color for active tab in dark theme." + :group 'awesome-tab + :type '(choice (const nil) string)) + +(defcustom awesome-tab-light-active-bar-color nil + "The bar color for active tab in light theme." + :group 'awesome-tab + :type '(choice (const nil) string)) + +(defcustom awesome-tab-dark-unselected-blend 0.8 + "The blend value for unselected background of dark mode. +Lower value means more contrast." + :group 'awesome-tab + :type 'float) + +(defcustom awesome-tab-light-unselected-blend 0.9 + "The blend value for unselected background of light mode. +Lower value means more contrast." + :group 'awesome-tab + :type 'float) + +(defcustom awesome-tab-active-bar-width 3 + "The width of active bar." + :group 'awesome-tab + :type 'integer) + +(defcustom awesome-tab-active-bar-height 30 + "The height of active bar." + :group 'awesome-tab + :type 'integer) + +(defvar-local awesome-tab-ace-state nil + "Whether current buffer is doing `awesome-tab-ace-jump' or not.") + +(defvar awesome-tab-hide-tab-function 'awesome-tab-hide-tab + "Function to hide tab. +This fucntion accepet tab name, tab will hide if this function return ni.") + +(defvar awesome-tab-current-tabset-function nil + "Function called with no argument to obtain the current tab set. +This is the tab set displayed on the tab bar.") + +(defvar awesome-tab-select-tab-function nil + "Function that select a tab. +The function is passed a tab, and should make it the +selected tab.") + +(defvar awesome-tab-buffer-list-function 'awesome-tab-buffer-list + "Function that returns the list of buffers to show in tabs. +That function is called with no arguments and must return a list of +buffers.") + +(defvar awesome-tab-buffer-groups-function 'awesome-tab-buffer-groups + "Function that gives the group names the current buffer belongs to. +It must return a list of group names, or nil if the buffer has no +group. Notice that it is better that a buffer belongs to one group.") + +(defvar awesome-tab-ace-1-key-seqs nil + "List of 1-key sequences used by `awesome-tab-ace-jump'") + +(defvar awesome-tab-ace-2-key-seqs nil + "List of 2-key sequences used by `awesome-tab-ace-jump'") + +(defvar awesome-tab-all-the-icons-is-load-p (ignore-errors (require 'all-the-icons)) + "Return non-nil if `all-the-icons' is load, `require' will have performance problem, so don't call it dynamically.") + +;;; Misc. +;; +(eval-and-compile + (defalias 'awesome-tab-display-update + (if (fboundp 'force-window-update) + #'(lambda () (force-window-update (selected-window))) + 'force-mode-line-update))) + +(defmacro awesome-tab-kill-buffer-match-rule (match-rule) + `(save-excursion + (mapc #'(lambda (buffer) + (with-current-buffer buffer + (when (string-equal current-group-name (cdr (awesome-tab-selected-tab (awesome-tab-current-tabset t)))) + (when (funcall ,match-rule buffer) + (kill-buffer buffer)) + ))) + (buffer-list)))) + +;; Copied from s.el +(defun awesome-tab-truncate-string (len s &optional ellipsis) + "If S is longer than LEN, cut it down and add ELLIPSIS to the end. + +The resulting string, including ellipsis, will be LEN characters +long. + +When not specified, ELLIPSIS defaults to ‘...’." + (declare (pure t) (side-effect-free t)) + (unless ellipsis + (setq ellipsis "...")) + (if (> (length s) len) + (format "%s%s" (substring s 0 (- len (length ellipsis))) ellipsis) + (concat s (make-string (- len (length s)) ? )))) + +(defun awesome-tab-refresh-display () + "Refresh the display of tabs. Put this in your user-defined hooks to +make sure the face colors are always right." + (interactive) + (awesome-tab-map-tabsets (lambda (x) (awesome-tab-set-template x nil))) + (awesome-tab-display-update)) + +;;; Tab and tab set +;; +(defsubst awesome-tab-make-tab (object tabset) + "Return a new tab with value OBJECT. +TABSET is the tab set the tab belongs to." + (cons object tabset)) + +(defsubst awesome-tab-tab-value (tab) + "Return the value of tab TAB." + (car tab)) + +(defsubst awesome-tab-tab-tabset (tab) + "Return the tab set TAB belongs to." + (cdr tab)) + +(defvar awesome-tab-tabsets nil + "The tab sets store.") + +(defvar awesome-tab-tabsets-tabset nil + "The special tab set of existing tab sets.") + +(defvar awesome-tab-current-tabset nil + "The tab set currently displayed on the tab bar.") +(make-variable-buffer-local 'awesome-tab-current-tabset) + +(defvar awesome-tab-init-hook nil + "Hook run after tab bar data has been initialized. +You should use this hook to initialize dependent data.") + +(defvar awesome-tab-active-bar nil) + +(defsubst awesome-tab-init-tabsets-store () + "Initialize the tab set store." + (setq awesome-tab-tabsets (make-vector 31 0) + awesome-tab-tabsets-tabset (make-symbol "awesome-tab-tabsets-tabset")) + (put awesome-tab-tabsets-tabset 'start 0) + (run-hooks 'awesome-tab-init-hook)) + +(defvar awesome-tab-quit-hook nil + "Hook run after tab bar data has been freed. +You should use this hook to reset dependent data.") + +(defsubst awesome-tab-free-tabsets-store () + "Free the tab set store." + (setq awesome-tab-tabsets nil + awesome-tab-tabsets-tabset nil) + (run-hooks 'awesome-tab-quit-hook)) + +;; Define an "hygienic" function free of side effect between its local +;; variables and those of the callee. +(eval-and-compile + (defalias 'awesome-tab-map-tabsets + (let ((function (make-symbol "function")) + (result (make-symbol "result")) + (tabset (make-symbol "tabset"))) + `(lambda (,function) + "Apply FUNCTION to each tab set, and make a list of the results. +The result is a list just as long as the number of existing tab sets." + (let (,result) + (mapatoms + #'(lambda (,tabset) + (push (funcall ,function ,tabset) ,result)) + awesome-tab-tabsets) + ,result))))) + +(defun awesome-tab-make-tabset (name &rest objects) + "Make a new tab set whose name is the string NAME. +It is initialized with tabs build from the list of OBJECTS." + (let* ((tabset (intern name awesome-tab-tabsets)) + (tabs (mapcar #'(lambda (object) + (awesome-tab-make-tab object tabset)) + objects))) + (set tabset tabs) + (put tabset 'select (car tabs)) + (put tabset 'start 0) + tabset)) + +(defsubst awesome-tab-get-tabset (name) + "Return the tab set whose name is the string NAME. +Return nil if not found." + (intern-soft name awesome-tab-tabsets)) + +(defsubst awesome-tab-delete-tabset (tabset) + "Delete the tab set TABSET. +That is, remove it from the tab sets store." + (unintern tabset awesome-tab-tabsets)) + +(defsubst awesome-tab-tabs (tabset) + "Return the list of tabs in TABSET." + (symbol-value tabset)) + +(defsubst awesome-tab-tab-values (tabset) + "Return the list of tab values in TABSET." + (mapcar 'awesome-tab-tab-value (awesome-tab-tabs tabset))) + +(defsubst awesome-tab-get-tab (object tabset) + "Search for a tab with value OBJECT in TABSET. +Return the tab found, or nil if not found." + (assoc object (awesome-tab-tabs tabset))) + +(defsubst awesome-tab-member (tab tabset) + "Return non-nil if TAB is in TABSET." + (or (eq (awesome-tab-tab-tabset tab) tabset) + (memq tab (awesome-tab-tabs tabset)))) + +(defsubst awesome-tab-template (tabset) + "Return the cached visual representation of TABSET. +That is, a `header-line-format' template, or nil if the cache is +empty." + (get tabset 'template)) + +(defsubst awesome-tab-set-template (tabset template) + "Set the cached visual representation of TABSET to TEMPLATE. +TEMPLATE must be a valid `header-line-format' template, or nil to +cleanup the cache." + (put tabset 'template template)) + +(defsubst awesome-tab-selected-tab (tabset) + "Return the tab selected in TABSET." + (get tabset 'select)) + +(defsubst awesome-tab-selected-value (tabset) + "Return the value of the tab selected in TABSET." + (awesome-tab-tab-value (awesome-tab-selected-tab tabset))) + +(defsubst awesome-tab-selected-p (tab tabset) + "Return non-nil if TAB is the selected tab in TABSET." + (eq tab (awesome-tab-selected-tab tabset))) + +(defvar awesome-tab--track-selected nil) + +(defsubst awesome-tab-select-tab (tab tabset) + "Make TAB the selected tab in TABSET. +Does nothing if TAB is not found in TABSET. +Return TAB if selected, nil if not." + (when (awesome-tab-member tab tabset) + (unless (awesome-tab-selected-p tab tabset) + (awesome-tab-set-template tabset nil) + (setq awesome-tab--track-selected awesome-tab-auto-scroll-flag)) + (put tabset 'select tab))) + +(defsubst awesome-tab-select-tab-value (object tabset) + "Make the tab with value OBJECT, the selected tab in TABSET. +Does nothing if a tab with value OBJECT is not found in TABSET. +Return the tab selected, or nil if nothing was selected." + (awesome-tab-select-tab (awesome-tab-get-tab object tabset) tabset)) + +(defsubst awesome-tab-start (tabset) + "Return the index of the first visible tab in TABSET." + (get tabset 'start)) + +(defsubst awesome-tab-view (tabset) + "Return the list of visible tabs in TABSET. +That is, the sub-list of tabs starting at the first visible one." + (nthcdr (awesome-tab-start tabset) (awesome-tab-tabs tabset))) + +(defun awesome-tab-add-tab (tabset object) + "Return tab if it has opend. +Otherwise insert new tab on right of current tab." + (let ((tabs (awesome-tab-tabs tabset))) + (if (awesome-tab-get-tab object tabset) + tabs + (let* ((tab (awesome-tab-make-tab object tabset)) + (selected (awesome-tab-selected-tab tabset)) + (selected-index (cl-position (car selected) (mapcar 'car tabs)))) + (awesome-tab-set-template tabset nil) + (set tabset (awesome-tab-insert-at tabs selected-index tab)) + )))) + +(defun awesome-tab-insert-at (list index insert-element) + (let ((counter 0) + (result '())) + (dolist (element list) + (if (equal counter index) + (setq result (append result (list element insert-element))) + (setq result (append result (list element)))) + (setq counter (+ 1 counter))) + result)) + +(defun awesome-tab-delete-tab (tab) + "Remove TAB from its tab set." + (let* ((tabset (awesome-tab-tab-tabset tab)) + (tabs (awesome-tab-tabs tabset)) + (sel (eq tab (awesome-tab-selected-tab tabset))) + (next (and sel (cdr (memq tab tabs))))) + (awesome-tab-set-template tabset nil) + (setq tabs (delq tab tabs)) + ;; When the selected tab is deleted, select the next one, if + ;; available, or the last one otherwise. + (and sel (awesome-tab-select-tab (car (or next (last tabs))) tabset)) + (set tabset tabs))) + +(defun awesome-tab-scroll (tabset count) + "Scroll the visible tabs in TABSET of COUNT units. +If COUNT is positive move the view on right. If COUNT is negative, +move the view on left." + (let ((start (min (max 0 (+ (awesome-tab-start tabset) count)) + (1- (length (awesome-tab-tabs tabset)))))) + (when (/= start (awesome-tab-start tabset)) + (awesome-tab-set-template tabset nil) + (put tabset 'start start)))) + +(defun awesome-tab-tab-next (tabset tab &optional before) + "Search in TABSET for the tab after TAB. +If optional argument BEFORE is non-nil, search for the tab before +TAB. Return the tab found, or nil otherwise." + (let* (last (tabs (awesome-tab-tabs tabset))) + (while (and tabs (not (eq tab (car tabs)))) + (setq last (car tabs) + tabs (cdr tabs))) + (and tabs (if before last (nth 1 tabs))))) + +(defun awesome-tab-current-tabset (&optional update) + "Return the tab set currently displayed on the tab bar. +If optional argument UPDATE is non-nil, call the user defined function +`awesome-tab-current-tabset-function' to obtain it. Otherwise return the +current cached copy." + (and update awesome-tab-current-tabset-function + (setq awesome-tab-current-tabset + (funcall awesome-tab-current-tabset-function))) + awesome-tab-current-tabset) + +(defun awesome-tab-get-tabsets-tabset () + "Return the tab set of selected tabs in existing tab sets." + (set awesome-tab-tabsets-tabset (awesome-tab-map-tabsets 'awesome-tab-selected-tab)) + (awesome-tab-scroll awesome-tab-tabsets-tabset 0) + (awesome-tab-set-template awesome-tab-tabsets-tabset nil) + awesome-tab-tabsets-tabset) + +;;; Faces +;; + +(defface awesome-tab-unselected-face + '((t)) + "Face used for unselected tabs. +Do not customize this. It's attribute will be calculated on the +fly to fit your theme." + :group 'awesome-tab) + +(defface awesome-tab-selected-face + '((t)) + "Face used for the selected tab. +Do not customize this. It's attribute will be calculated on the +fly to fit your theme." + :group 'awesome-tab) + +(defface awesome-tab-unselected-ace-face + '((t (:inherit 'font-lock-function-name-face))) + "Face used for ace string on unselected tabs. +Note that the background will be calculated on the fly, so +customize the background will not have any effect." + :group 'awesome-tab) + +(defface awesome-tab-selected-ace-face + '((t (:inherit 'font-lock-function-name-face))) + "Face used for ace string on selected tabs. +Note that the background will be calculated on the fly, so +customize the background will not have any effect." + :group 'awesome-tab) + +(defface awesome-tab-unselected-index-face + '((t (:inherit 'font-lock-function-name-face))) + "Face used for index on unselected tabs. +Note that the background will be calculated on the fly, so +customize the background will not have any effect." + :group 'awesome-tab) + +(defface awesome-tab-selected-index-face + '((t (:inherit 'font-lock-function-name-face))) + "Face used for index on selected tabs. +Note that the background will be calculated on the fly, so +customize the background will not have any effect." + :group 'awesome-tab) + +;;; Tabs +;; +(defun awesome-tab-make-header-line-mouse-map (mouse function) + (let ((map (make-sparse-keymap))) + (define-key map (vector 'header-line mouse) function) + map)) + +(defun awesome-tab-color-blend (c1 c2 alpha) + "Blend two colors C1 and C2 with ALPHA. +C1 and C2 are hexidecimal strings. +ALPHA is a number between 0.0 and 1.0 which corresponds to the +influence of C1 on the result." + (apply #'(lambda (r g b) + (format "#%02x%02x%02x" + (ash r -8) + (ash g -8) + (ash b -8))) + (cl-mapcar + (lambda (x y) + (round (+ (* x alpha) (* y (- 1 alpha))))) + (color-values c1) (color-values c2)))) + +(defun awesome-tab-adjust-color-with-theme () + "We need adjust awesome-tab's colors when user switch new theme." + (let* ((bg-mode (frame-parameter nil 'background-mode)) + (select-tab-background (awesome-tab-get-select-background-color)) + (unselect-tab-background (awesome-tab-get-unslect-background-color))) + (when (display-graphic-p) + (setq awesome-tab-active-bar (awesome-tab-make-xpm awesome-tab-active-bar-width awesome-tab-active-bar-height))) + + (set-face-attribute 'header-line nil :height awesome-tab-height) + + (set-face-attribute 'awesome-tab-selected-face nil + :foreground (awesome-tab-get-select-foreground-color) + :distant-foreground (awesome-tab-get-select-foreground-color) + :background select-tab-background) + (set-face-attribute 'awesome-tab-unselected-face nil + :foreground (awesome-tab-get-unselect-foreground-color) + :distant-foreground (awesome-tab-get-unselect-foreground-color) + :background unselect-tab-background) + + (set-face-attribute 'awesome-tab-selected-ace-face nil + :background select-tab-background) + (set-face-attribute 'awesome-tab-unselected-ace-face nil + :background unselect-tab-background) + + (set-face-attribute 'awesome-tab-selected-index-face nil + :background select-tab-background) + (set-face-attribute 'awesome-tab-unselected-index-face nil + :background unselect-tab-background))) + +(defun awesome-tab-get-select-foreground-color () + (let ((bg-mode (frame-parameter nil 'background-mode))) + (if (display-graphic-p) + (cond ((eq bg-mode 'dark) (or awesome-tab-dark-selected-foreground-color + (face-foreground 'font-lock-doc-face))) + ((eq bg-mode 'light) (or awesome-tab-light-selected-foreground-color + (face-foreground 'font-lock-doc-face)))) + (cond ((eq bg-mode 'dark) awesome-tab-terminal-dark-select-foreground-color) + ((eq bg-mode 'light) awesome-tab-terminal-light-select-foreground-color)) + ))) + +(defun awesome-tab-get-unselect-foreground-color () + (let ((bg-mode (frame-parameter nil 'background-mode))) + (if (display-graphic-p) + (cond ((eq bg-mode 'dark) (or awesome-tab-dark-unselected-foreground-color + (face-foreground 'font-lock-comment-face))) + ((eq bg-mode 'light) (or awesome-tab-light-unselected-foreground-color + (face-foreground 'font-lock-comment-face)))) + (cond ((eq bg-mode 'dark) awesome-tab-terminal-dark-unselect-foreground-color) + ((eq bg-mode 'light) awesome-tab-terminal-light-unselect-foreground-color)) + ))) + +(defun awesome-tab-get-select-background-color () + (let ((bg-mode (frame-parameter nil 'background-mode))) + (if (display-graphic-p) + (face-background 'default) + (cond ((eq bg-mode 'dark) awesome-tab-terminal-dark-select-background-color) + ((eq bg-mode 'light) awesome-tab-terminal-light-select-background-color)) + ))) + +(defun awesome-tab-get-unslect-background-color () + (let* ((bg-mode (frame-parameter nil 'background-mode))) + (if (display-graphic-p) + (cond ((eq bg-mode 'dark) + (awesome-tab-color-blend (face-background 'default) "#000000" awesome-tab-dark-unselected-blend)) + ((eq bg-mode 'light) + (awesome-tab-color-blend (face-background 'default) "#000000" awesome-tab-light-unselected-blend))) + (cond ((eq bg-mode 'dark) awesome-tab-terminal-dark-unselect-background-color) + ((eq bg-mode 'light) awesome-tab-terminal-light-unselect-background-color)) + ))) + +(defun awesome-tab-line-format (tabset) + "Return the `header-line-format' value to display TABSET." + ;; Adjust color with theme. + (awesome-tab-adjust-color-with-theme) + ;; Reder tab line. + (let* ((sel (awesome-tab-selected-tab tabset)) + (tabs (awesome-tab-view tabset)) + (bg-mode (frame-parameter nil 'background-mode)) + (header-line-color (awesome-tab-get-unslect-background-color)) + atsel elts) + ;; Track the selected tab to ensure it is always visible. + (when awesome-tab--track-selected + (while (not (memq sel tabs)) + (awesome-tab-scroll tabset -1) + (setq tabs (awesome-tab-view tabset))) + (while (and tabs (not atsel)) + (setq elts (cons (awesome-tab-line-tab (car tabs)) elts) + atsel (eq (car tabs) sel) + tabs (cdr tabs))) + (setq elts (nreverse elts)) + ;; At this point the selected tab is the last elt in ELTS. + ;; Scroll TABSET and ELTS until the selected tab becomes + ;; visible. + (let (buffer-list-update-hook) + (with-temp-buffer + (let ((truncate-partial-width-windows nil) + (inhibit-modification-hooks t) + deactivate-mark ;; Prevent deactivation of the mark! + start) + (setq truncate-lines nil + buffer-undo-list t) + (setq start (point)) + (while (and (cdr elts) ;; Always show the selected tab! + (progn + (delete-region start (point-max)) + (goto-char (point-max)) + (apply 'insert elts) + (goto-char (point-min)) + (> (vertical-motion 1) 0))) + (awesome-tab-scroll tabset 1) + (setq elts (cdr elts)))))) + (setq elts (nreverse elts)) + (setq awesome-tab--track-selected nil)) + ;; Format remaining tabs. + (while tabs + (setq elts (cons (awesome-tab-line-tab (car tabs)) elts) + tabs (cdr tabs))) + ;; Cache and return the new tab bar. + (awesome-tab-set-template + tabset + (list (nreverse elts) + (propertize "%-" + 'face (list :background header-line-color + :foreground header-line-color + :distant-foreground header-line-color) + 'pointer 'arrow))))) + +(defun awesome-tab-line () + "Return the header line templates that represent the tab bar. +Inhibit display of the tab bar in current window `awesome-tab-hide-tab-function' return nil." + (cond + ((awesome-tab-hide-tab-cached (current-buffer)) + ;; Don't show the tab bar. + (setq header-line-format nil)) + ((awesome-tab-current-tabset t) + ;; When available, use a cached tab bar value, else recompute it. + (or (awesome-tab-template awesome-tab-current-tabset) + (awesome-tab-line-format awesome-tab-current-tabset))))) + +(defconst awesome-tab-header-line-format '(:eval (awesome-tab-line)) + "The tab bar header line format.") + +;;; Cyclic navigation through tabs +;; +(defun awesome-tab-cycle (&optional backward type) + "Cycle to the next available tab. +The scope of the cyclic navigation through tabs is specified by the +option `awesome-tab-cycle-scope'. +If optional argument BACKWARD is non-nil, cycle to the previous tab +instead." + (let* ((tabset (awesome-tab-current-tabset t)) + (ttabset (awesome-tab-get-tabsets-tabset)) + ;; If navigation through groups is requested, and there is + ;; only one group, navigate through visible tabs. + (cycle (if (and (eq awesome-tab-cycle-scope 'groups) + (not (cdr (awesome-tab-tabs ttabset)))) + 'tabs + awesome-tab-cycle-scope)) + selected tab) + (when tabset + (setq selected (awesome-tab-selected-tab tabset)) + (cond + ;; Cycle through visible tabs only. + ((eq cycle 'tabs) + (setq tab (awesome-tab-tab-next tabset selected backward)) + ;; When there is no tab after/before the selected one, cycle + ;; to the first/last visible tab. + (unless tab + (setq tabset (awesome-tab-tabs tabset) + tab (car (if backward (last tabset) tabset)))) + ) + ;; Cycle through tab groups only. + ((eq cycle 'groups) + (setq tab (awesome-tab-tab-next ttabset selected backward)) + ;; When there is no group after/before the selected one, cycle + ;; to the first/last available group. + (unless tab + (setq tabset (awesome-tab-tabs ttabset) + tab (car (if backward (last tabset) tabset)))) + ) + (t + ;; Cycle through visible tabs then tab groups. + (setq tab (awesome-tab-tab-next tabset selected backward)) + ;; When there is no visible tab after/before the selected one, + ;; cycle to the next/previous available group. + (unless tab + (setq tab (awesome-tab-tab-next ttabset selected backward)) + ;; When there is no next/previous group, cycle to the + ;; first/last available group. + (unless tab + (setq tabset (awesome-tab-tabs ttabset) + tab (car (if backward (last tabset) tabset)))) + ;; Select the first/last visible tab of the new group. + (setq tabset (awesome-tab-tabs (awesome-tab-tab-tabset tab)) + tab (car (if backward (last tabset) tabset)))) + )) + (awesome-tab-buffer-select-tab tab)))) + +;;;###autoload +(defun awesome-tab-backward () + "Select the previous available tab. +Depend on the setting of the option `awesome-tab-cycle-scope'." + (interactive) + (awesome-tab-cycle t)) + +;;;###autoload +(defun awesome-tab-forward () + "Select the next available tab. +Depend on the setting of the option `awesome-tab-cycle-scope'." + (interactive) + (awesome-tab-cycle)) + +;;;###autoload +(defun awesome-tab-backward-group () + "Go to selected tab in the previous available group." + (interactive) + (let ((awesome-tab-cycle-scope 'groups)) + (awesome-tab-cycle t))) + +;;;###autoload +(defun awesome-tab-forward-group () + "Go to selected tab in the next available group." + (interactive) + (let ((awesome-tab-cycle-scope 'groups)) + (awesome-tab-cycle))) + +;;;###autoload +(defun awesome-tab-backward-tab () + "Select the previous visible tab." + (interactive) + (let ((awesome-tab-cycle-scope 'tabs)) + (awesome-tab-cycle t))) + +;;;###autoload +(defun awesome-tab-forward-tab () + "Select the next visible tab." + (interactive) + (let ((awesome-tab-cycle-scope 'tabs)) + (awesome-tab-cycle))) + +;;; Minor modes +;; +(defsubst awesome-tab-mode-on-p () + "Return non-nil if Awesome-Tab mode is on." + (eq (default-value 'header-line-format) + awesome-tab-header-line-format)) + +;;; Awesome-Tab mode +;; +(defvar awesome-tab-mode-map + (let ((km (make-sparse-keymap))) + km) + "Keymap to use in Awesome-Tab mode.") + +(defvar awesome-tab--global-hlf nil) + +;;;###autoload +(define-minor-mode awesome-tab-mode + "Toggle display of a tab bar in the header line. +With prefix argument ARG, turn on if positive, otherwise off. +Returns non-nil if the new state is enabled. + +\\{awesome-tab-mode-map}" + :group 'awesome-tab + :require 'awesome-tab + :global t + :keymap awesome-tab-mode-map + (if awesome-tab-mode +;;; ON + (unless (awesome-tab-mode-on-p) + ;; Save current default value of `header-line-format'. + (setq awesome-tab--global-hlf (default-value 'header-line-format)) + (awesome-tab-init-tabsets-store) + (setq-default header-line-format awesome-tab-header-line-format)) +;;; OFF + (when (awesome-tab-mode-on-p) + ;; Restore previous `header-line-format'. + (setq-default header-line-format awesome-tab--global-hlf) + (awesome-tab-free-tabsets-store)) + )) + +;;; Buffer tabs +;; +(defgroup awesome-tab-buffer nil + "Display buffers in the tab bar." + :group 'awesome-tab) + +(defun awesome-tab-filter (condp lst) + (delq nil + (mapcar (lambda (x) (and (funcall condp x) x)) lst))) + +(defun awesome-tab-filter-out (condp lst) + (delq nil + (mapcar (lambda (x) (if (funcall condp x) nil x)) lst))) + +(defun awesome-tab-buffer-list () + "Return the list of buffers to show in tabs. +Exclude buffers whose name starts with a space, when they are not +visiting a file. The current buffer is always included." + (awesome-tab-filter-out + 'awesome-tab-hide-tab-cached + (delq nil + (mapcar #'(lambda (b) + (cond + ;; Always include the current buffer. + ((eq (current-buffer) b) b) + ((buffer-file-name b) b) + ((char-equal ?\ (aref (buffer-name b) 0)) nil) + ((buffer-live-p b) b))) + (buffer-list))))) + +(defun awesome-tab-buffer-mode-derived-p (mode parents) + "Return non-nil if MODE derives from a mode in PARENTS." + (let (derived) + (while (and (not derived) mode) + (if (memq mode parents) + (setq derived t) + (setq mode (get mode 'derived-mode-parent)))) + derived)) + +;;; Group buffers in tab sets. +;; +(defvar awesome-tab--buffers nil) + +(defun awesome-tab-buffer-update-groups () + "Update tab sets from groups of existing buffers. +Return the the first group where the current buffer is." + (let ((bl (sort + (mapcar + #'(lambda (b) + (with-current-buffer b + (list (current-buffer) + (buffer-name) + (if awesome-tab-buffer-groups-function + (funcall awesome-tab-buffer-groups-function) + '(awesome-tab-common-group-name))))) + (and awesome-tab-buffer-list-function + (funcall awesome-tab-buffer-list-function))) + #'(lambda (e1 e2) + (string-lessp (nth 1 e1) (nth 1 e2)))))) + ;; If the cache has changed, update the tab sets. + (unless (equal bl awesome-tab--buffers) + ;; Add new buffers, or update changed ones. + (dolist (e bl) + (dolist (g (nth 2 e)) + (let ((tabset (awesome-tab-get-tabset g))) + (if tabset + (unless (equal e (assq (car e) awesome-tab--buffers)) + ;; This is a new buffer, or a previously existing + ;; buffer that has been renamed, or moved to another + ;; group. Update the tab set, and the display. + (awesome-tab-add-tab tabset (car e)) + (awesome-tab-set-template tabset nil)) + (awesome-tab-make-tabset g (car e)))))) + ;; Remove tabs for buffers not found in cache or moved to other + ;; groups, and remove empty tabsets. + (mapc 'awesome-tab-delete-tabset + (awesome-tab-map-tabsets + #'(lambda (tabset) + (dolist (tab (awesome-tab-tabs tabset)) + (let ((e (assq (awesome-tab-tab-value tab) bl))) + (or (and e (memq tabset + (mapcar 'awesome-tab-get-tabset + (nth 2 e)))) + (awesome-tab-delete-tab tab)))) + ;; Return empty tab sets + (unless (awesome-tab-tabs tabset) + tabset)))) + ;; The new cache becomes the current one. + (setq awesome-tab--buffers bl))) + ;; Return the first group the current buffer belongs to. + (car (nth 2 (assq (current-buffer) awesome-tab--buffers)))) + +;;; Tab bar callbacks +;; +(defvar awesome-tab--buffer-show-groups nil) + +(defsubst awesome-tab-buffer-show-groups (flag) + "Set display of tabs for groups of buffers to FLAG." + (setq awesome-tab--buffer-show-groups flag)) + +(defun awesome-tab-buffer-tabs () + "Return the buffers to display on the tab bar, in a tab set." + (let ((tabset (awesome-tab-get-tabset (awesome-tab-buffer-update-groups)))) + (awesome-tab-select-tab-value (current-buffer) tabset) + (when awesome-tab--buffer-show-groups + (setq tabset (awesome-tab-get-tabsets-tabset)) + (awesome-tab-select-tab-value (current-buffer) tabset)) + tabset)) + +(defsubst awesome-tab-line-tab (tab) + "Return the display representation of tab TAB. +That is, a propertized string used as an `header-line-format' template +element." + (propertize + (awesome-tab-buffer-tab-label tab) + 'pointer 'hand + 'local-map (purecopy (awesome-tab-make-header-line-mouse-map + 'mouse-1 + `(lambda (event) (interactive "e") + (let ((tab-window (window-at (cadr (mouse-position)) + (cddr (mouse-position)) + (car (mouse-position))))) + (when tab-window + (select-window tab-window) + (awesome-tab-buffer-select-tab ',tab)))))))) + +(defun awesome-tab-buffer-tab-label (tab) + "Return a label for TAB. +That is, a string used to represent it on the tab bar." + (let* ((is-active-tab (awesome-tab-selected-p tab (awesome-tab-current-tabset))) + (tab-face (if is-active-tab 'awesome-tab-selected-face 'awesome-tab-unselected-face)) + (index-face (if is-active-tab 'awesome-tab-selected-index-face 'awesome-tab-unselected-index-face)) + (current-buffer-index (cl-position tab (awesome-tab-view (awesome-tab-current-tabset t)))) + (ace-str-face (if is-active-tab 'awesome-tab-selected-ace-face 'awesome-tab-unselected-ace-face)) + (current-buffer-index (cl-position tab (awesome-tab-view awesome-tab-current-tabset))) + (ace-str (if awesome-tab-ace-state (elt ace-strs current-buffer-index) "")) + (ace-state awesome-tab-ace-state)) + (concat + ;; Active bar. + (when (and is-active-tab awesome-tab-active-bar) + (propertize awesome-tab-active-bar)) + ;; Ace string. + (when (and ace-state (eq awesome-tab-ace-str-style 'left)) + (propertize ace-str 'face ace-str-face)) + ;; Tab icon. + (when (and awesome-tab-display-icon + awesome-tab-all-the-icons-is-load-p) + (propertize " " 'face tab-face)) + (if (and ace-state (eq awesome-tab-ace-str-style 'replace-icon)) + (propertize ace-str 'face ace-str-face) + (awesome-tab-icon-for-tab tab tab-face)) + ;; Tab label. + (propertize (awesome-tab-tab-name tab) 'face tab-face) + ;; Ace string. + (when (and ace-state (eq awesome-tab-ace-str-style 'right)) + (propertize ace-str 'face ace-str-face)) + ;; Tab index. + (when awesome-tab-show-tab-index + (propertize (format awesome-tab-index-format-str (+ current-buffer-index 1)) 'face index-face)) + ))) + +(defun awesome-tab-make-xpm (width height) + "Create an XPM bitmap via WIDTH and HEIGHT." + (when (and (display-graphic-p) + (image-type-available-p 'xpm)) + (propertize + " " 'display + (let ((data (make-list height (make-list width 1))) + (color (pcase (frame-parameter nil 'background-mode) + ('dark (or awesome-tab-dark-active-bar-color + (face-background 'highlight))) + ('light (or awesome-tab-light-active-bar-color + (face-background 'highlight)))))) + (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)))))) + +(defun awesome-tab-tab-name (tab) + "Render tab's name. +Tab name will truncate if option `awesome-tab-truncate-string' big than zero." + (format " %s " + (let ((bufname (awesome-tab-buffer-name (car tab)))) + (cond ((> awesome-tab-label-fixed-length 0) + (awesome-tab-truncate-string awesome-tab-label-fixed-length bufname)) + ((> awesome-tab-label-max-length 0) + (let ((ellipsis "...")) + (if (> (length bufname) awesome-tab-label-max-length) + (format "%s%s" (substring bufname 0 (- awesome-tab-label-max-length (length ellipsis))) ellipsis) + bufname))) + (t + bufname)) + ))) + +(defun awesome-tab-icon-for-tab (tab face) + "When tab buffer's file is exists, use `all-the-icons-icon-for-file' to fetch file icon. +Otherwise use `all-the-icons-icon-for-buffer' to fetch icon for buffer." + (when (and awesome-tab-display-icon + awesome-tab-all-the-icons-is-load-p) + (let* ((tab-buffer (car tab)) + (tab-file (buffer-file-name tab-buffer)) + (background (face-background face)) + (icon + (cond + ;; Use `all-the-icons-icon-for-file' if current file is exists. + ((and + tab-file + (file-exists-p tab-file)) + (all-the-icons-icon-for-file tab-file :v-adjust awesome-tab-icon-v-adjust :height awesome-tab-icon-height)) + ;; Use `all-the-icons-icon-for-mode' for current tab buffer at last. + (t + (with-current-buffer tab-buffer + (if (derived-mode-p tab-buffer 'eaf-mode) + (all-the-icons-faicon "html5" :v-adjust awesome-tab-icon-v-adjust :height awesome-tab-icon-height) + (all-the-icons-icon-for-mode major-mode :v-adjust awesome-tab-icon-v-adjust :height awesome-tab-icon-height)) + ))))) + (when (and icon + ;; `get-text-property' need icon is string type. + (stringp icon)) + ;; Thanks ema2159 for code block ;) + (propertize icon 'face `(:inherit ,(get-text-property 0 'face icon) :background ,background)))))) + +(defun awesome-tab-buffer-name (tab-buffer) + "Get buffer name of tab. +Will merge sticky function name in tab if option `awesome-tab-display-sticky-function-name' is non-nil." + (if (and awesome-tab-display-sticky-function-name + (boundp 'awesome-tab-last-sticky-func-name) + awesome-tab-last-sticky-func-name + (equal tab-buffer (current-buffer))) + (format "%s [%s]" (buffer-name tab-buffer) awesome-tab-last-sticky-func-name) + (buffer-name tab-buffer))) + +(defvar awesome-tab-last-scroll-y 0 + "Holds the scroll y of window from the last run of post-command-hooks.") + +(defun awesome-tab-monitor-window-scroll () + "This function is used to monitor the window scroll. +Currently, this function is only use for option `awesome-tab-display-sticky-function-name'." + (when awesome-tab-display-sticky-function-name + (let ((scroll-y (window-start))) + (when (and scroll-y + (integerp scroll-y)) + (unless (equal scroll-y awesome-tab-last-scroll-y) + (let ((func-name (save-excursion + (goto-char scroll-y) + (require 'which-func) + (which-function)))) + (when (or + (not (boundp 'awesome-tab-last-sticky-func-name)) + (not (equal func-name awesome-tab-last-sticky-func-name))) + (set (make-local-variable 'awesome-tab-last-sticky-func-name) func-name) + + ;; Use `ignore-errors' avoid integerp error when execute `awesome-tab-line-format'. + (ignore-errors + (awesome-tab-line-format awesome-tab-current-tabset)) + )))) + (setq awesome-tab-last-scroll-y scroll-y)))) + +(add-hook 'post-command-hook 'awesome-tab-monitor-window-scroll) + +(defun awesome-tab-buffer-select-tab (tab) + "Select tab." + (let ((buffer (awesome-tab-tab-value tab))) + (switch-to-buffer buffer) + (awesome-tab-buffer-show-groups nil) + (awesome-tab-display-update) + )) + +(defun awesome-tab-buffer-track-killed () + "Hook run just before actually killing a buffer. +In Awesome-Tab mode, try to switch to a buffer in the current tab bar, +after the current buffer has been killed. Try first the buffer in tab +after the current one, then the buffer in tab before. On success, put +the sibling buffer in front of the buffer list, so it will be selected +first." + (and (eq header-line-format awesome-tab-header-line-format) + (eq awesome-tab-current-tabset-function 'awesome-tab-buffer-tabs) + (eq (current-buffer) (window-buffer (selected-window))) + (let ((bl (awesome-tab-tab-values (awesome-tab-current-tabset))) + (b (current-buffer)) + found sibling) + (while (and bl (not found)) + (if (eq b (car bl)) + (setq found t) + (setq sibling (car bl))) + (setq bl (cdr bl))) + (when (and (setq sibling (or (car bl) sibling)) + (buffer-live-p sibling)) + ;; Move sibling buffer in front of the buffer list. + (save-current-buffer + (switch-to-buffer sibling)))))) + +;;; Tab bar buffer setup +;; +(defun awesome-tab-buffer-init () + "Initialize tab bar buffer data. +Run as `awesome-tab-init-hook'." + (setq awesome-tab--buffers nil + awesome-tab--buffer-show-groups nil + awesome-tab-current-tabset-function 'awesome-tab-buffer-tabs + awesome-tab-select-tab-function 'awesome-tab-buffer-select-tab + ) + (add-hook 'kill-buffer-hook 'awesome-tab-buffer-track-killed)) + +(defun awesome-tab-buffer-quit () + "Quit tab bar buffer. +Run as `awesome-tab-quit-hook'." + (setq awesome-tab--buffers nil + awesome-tab--buffer-show-groups nil + awesome-tab-current-tabset-function nil + awesome-tab-select-tab-function nil + ) + (remove-hook 'kill-buffer-hook 'awesome-tab-buffer-track-killed)) + +(add-hook 'awesome-tab-init-hook 'awesome-tab-buffer-init) +(add-hook 'awesome-tab-quit-hook 'awesome-tab-buffer-quit) + +;;;;;;;;;;;;;;;;;;;;;;; Interactive functions ;;;;;;;;;;;;;;;;;;;;;;; +(defun awesome-tab-switch-group (&optional groupname) + "Switch tab groups using ido." + (interactive) + (let* ((tab-buffer-list (mapcar + #'(lambda (b) + (with-current-buffer b + (list (current-buffer) + (buffer-name) + (funcall awesome-tab-buffer-groups-function) ))) + (funcall awesome-tab-buffer-list-function))) + (groups (awesome-tab-get-groups)) + (group-name (or groupname + (completing-read "Switch to group: " + groups nil t))) ) + (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 awesome-tab-select-end-tab () + "Select end tab of current tabset." + (interactive) + (awesome-tab-select-beg-tab t)) + +(defun awesome-tab-select-beg-tab (&optional backward type) + "Select beginning tab of current tabs. +If BACKWARD is non-nil, move backward, otherwise move forward. +TYPE is default option." + (interactive) + (let* ((tabset (awesome-tab-current-tabset t)) + (ttabset (awesome-tab-get-tabsets-tabset)) + (cycle (if (and (eq awesome-tab-cycle-scope 'groups) + (not (cdr (awesome-tab-tabs ttabset)))) + 'tabs + awesome-tab-cycle-scope)) + selected tab) + (when tabset + (setq selected (awesome-tab-selected-tab tabset)) + (setq tabset (awesome-tab-tabs tabset) + tab (car (if backward (last tabset) tabset))) + (awesome-tab-buffer-select-tab tab)))) + +(defun awesome-tab-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 + (awesome-tab-forward-tab) + (awesome-tab-backward-tab)) + (other-window -1)) + +(defun awesome-tab-forward-tab-other-window () + "Move to right tab in other window." + (interactive) + (awesome-tab-backward-tab-other-window t)) + +(defun awesome-tab-move-current-tab-to-right () + "Move current tab one place right, unless it's already the rightmost." + (interactive) + (let* ((bufset (awesome-tab-current-tabset t)) + (old-bufs (awesome-tab-tabs bufset)) + (first-buf (car old-bufs)) + (new-bufs (list))) + (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 Awesome-Tab's buffer list.")) + (setq new-bufs (reverse new-bufs)) + (setq new-bufs (append new-bufs (cdr old-bufs))) + (set bufset new-bufs) + (awesome-tab-set-template bufset nil) + (awesome-tab-display-update))) + +(defun awesome-tab-move-current-tab-to-left () + "Move current tab one place left, unless it's already the leftmost." + (interactive) + (let* ((bufset (awesome-tab-current-tabset t)) + (old-bufs (awesome-tab-tabs bufset)) + (first-buf (car old-bufs)) + (new-bufs (list))) + (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 Awesome-Tab's buffer list.")) + (set bufset new-bufs) + (awesome-tab-set-template bufset nil) + (awesome-tab-display-update)))) + +(defun awesome-tab-move-current-tab-to-beg () + "Move current tab to the first position." + (interactive) + (let* ((bufset (awesome-tab-current-tabset t)) + (bufs (copy-sequence (awesome-tab-tabs bufset))) + (current-tab-index + (cl-position (current-buffer) (mapcar #'car bufs))) + (current-tab (elt bufs current-tab-index))) + (setq bufs (delete current-tab bufs)) + (push current-tab bufs) + (set bufset bufs) + (awesome-tab-set-template bufset nil) + (awesome-tab-display-update))) + +(defun awesome-tab-kill-all-buffers-in-current-group () + "Kill all buffers in current group." + (interactive) + (let* ((current-group-name (cdr (awesome-tab-selected-tab (awesome-tab-current-tabset t))))) + ;; Kill all buffers in current group. + (awesome-tab-kill-buffer-match-rule + (lambda (buffer) t)) + ;; Switch to next group. + (awesome-tab-forward-group) + )) + +(defun awesome-tab-kill-other-buffers-in-current-group () + "Kill all buffers except current buffer in current group." + (interactive) + (let* ((current-group-name (cdr (awesome-tab-selected-tab (awesome-tab-current-tabset t)))) + (currentbuffer (current-buffer))) + ;; Kill all buffers in current group. + (awesome-tab-kill-buffer-match-rule + (lambda (buffer) (not (equal buffer currentbuffer)))) + )) + +(defun awesome-tab-kill-match-buffers-in-current-group () + "Kill all buffers match extension in current group." + (interactive) + (let* ((current-group-name (cdr (awesome-tab-selected-tab (awesome-tab-current-tabset t)))) + (extension-names (awesome-tab-get-extensions)) + match-extension) + ;; Read extension need to kill. + (setq match-extension (completing-read "Kill buffers suffix with: " + extension-names nil t)) + ;; Kill all buffers match extension in current group. + (awesome-tab-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) + (awesome-tab-forward-group)) + )) + +(defun awesome-tab-keep-match-buffers-in-current-group () + "Keep all buffers match extension in current group." + (interactive) + (let* ((current-group-name (cdr (awesome-tab-selected-tab (awesome-tab-current-tabset t)))) + (extension-names (awesome-tab-get-extensions)) + match-extension) + ;; Read extension need to kill. + (setq match-extension (completing-read "Keep buffers suffix with: " + extension-names nil t)) + ;; Kill all buffers match extension in current group. + (awesome-tab-kill-buffer-match-rule + (lambda (buffer) + (let ((filename (buffer-file-name buffer))) + (and filename (not (string-equal (file-name-extension filename) match-extension))) + ))))) + +(defun awesome-tab-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 (awesome-tab-view awesome-tab-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 awesome-tab-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)) + (tab-index (string-to-number + ;; Fix issue #81 that `last-command-event' is not keystroke. + (cond ((equal (length key-desc) 1) + key-desc) + (t + (nth 1 (split-string key-desc "-"))))))) + (awesome-tab-select-visible-nth-tab tab-index))) + +(defun awesome-tab-build-ace-strs (len key-number seqs) + "Build strings for `awesome-tab-ace-jump'. +LEN is the number of strings, should be the number of current visible +tabs. NKEYS should be 1 or 2." + (let ((i 0) + (str nil)) + (when (>= key-number 3) + (error "NKEYS should be 1 or 2")) + (while (< i len) + (push (apply #'string (elt seqs i)) str) + (setq i (1+ i))) + (nreverse str))) + +(defun awesome-tab-open-tab-in-current-group () + "Open a tab in current group." + (interactive) + (let* ((generate-candidate (lambda (tab) + (propertize + (string-trim (awesome-tab-tab-name tab)) + 'awesome-tab-tab-entity tab))) + (candidates (mapcar generate-candidate + (awesome-tab-tabs (awesome-tab-current-tabset))))) + (awesome-tab-buffer-select-tab + (get-text-property 0 'awesome-tab-tab-entity + (completing-read "Open tab:" candidates nil t))))) + +(defun awesome-tab-ace-jump () + "Jump to a visible tab by 1 or 2 chars." + (interactive) + (catch 'quit + (let* ((visible-tabs (awesome-tab-view awesome-tab-current-tabset)) + (visible-tabs-length (length visible-tabs)) + done-flag + (lower-bound 0) + (upper-bound visible-tabs-length) + (ace-keys (length awesome-tab-ace-keys)) + (key-number (cond + ((<= visible-tabs-length ace-keys) 1) + ((<= visible-tabs-length (* ace-keys ace-keys)) 2) + (t (error "Too many visible tabs. Put more keys into `awesome-tab-ace-keys'.")))) + (visible-seqs + (cl-subseq + (symbol-value + (intern + (concat "awesome-tab-ace-" (number-to-string key-number) "-key-seqs"))) + 0 visible-tabs-length)) + (ace-strs (awesome-tab-build-ace-strs visible-tabs-length key-number visible-seqs))) + (setq awesome-tab-ace-state t) + (awesome-tab-refresh-display) + (dotimes (i key-number) + (while (not done-flag) + (let ((char (with-local-quit (read-key (format "Awesome Tab Ace Jump (%d):" (1+ i)))))) + (if (not (member char awesome-tab-ace-quit-keys)) + (let ((current-chars (mapcar #'car visible-seqs))) + (when (member char current-chars) + (setq done-flag t) + (setq lower-bound (cl-position char current-chars)) + (setq upper-bound (1- (- visible-tabs-length (cl-position char (nreverse current-chars))))) + (dotimes (lower-index lower-bound) + (setcar (nthcdr lower-index visible-seqs) nil)) + (setq upper-index (1+ upper-bound)) + (while (< upper-index visible-tabs-length) + (setcar (nthcdr upper-index visible-seqs) nil) + (setq upper-index (1+ upper-index))) + (setq upper-index 0) + )) + ;; Quit when user press Ctrl + g. + (setq awesome-tab-ace-state nil) + (awesome-tab-refresh-display) + (throw 'quit nil)))) + (setq done-flag nil) + (setq visible-seqs (mapcar #'cdr visible-seqs)) + (setq ace-strs (awesome-tab-build-ace-strs visible-tabs-length key-number visible-seqs)) + (awesome-tab-refresh-display)) + (setq awesome-tab-ace-state nil) + (awesome-tab-refresh-display) + (awesome-tab-buffer-select-tab (nth lower-bound visible-tabs))))) + +;;;;;;;;;;;;;;;;;;;;;;; Utils functions ;;;;;;;;;;;;;;;;;;;;;;; +(defun awesome-tab-get-groups () + ;; Refresh groups. + (set awesome-tab-tabsets-tabset (awesome-tab-map-tabsets 'awesome-tab-selected-tab)) + (mapcar #'(lambda (group) + (format "%s" (cdr group))) + (awesome-tab-tabs awesome-tab-tabsets-tabset))) + +(defun awesome-tab-get-extensions () + ;; Refresh groups. + (set awesome-tab-tabsets-tabset (awesome-tab-map-tabsets 'awesome-tab-selected-tab)) + (let ((extension-names '())) + (mapc #'(lambda (buffer) + (with-current-buffer buffer + (when (string-equal current-group-name (cdr (awesome-tab-selected-tab (awesome-tab-current-tabset t)))) + (when (buffer-file-name buffer) + (add-to-list 'extension-names (file-name-extension (buffer-file-name buffer)))) + ))) + (buffer-list)) + extension-names)) + +;;;;;;;;;;;;;;;;;;;;;;; Default configurations ;;;;;;;;;;;;;;;;;;;;;;; + +;; Uniquify tab name when open multiple buffers with same filename. +(setq uniquify-separator "/") +(setq uniquify-buffer-name-style 'post-forward-angle-brackets) +(setq uniquify-after-kill-buffer-p t) + +(dolist (hook awesometab-hide-tabs-hooks) + (add-hook hook '(lambda () (setq-local header-line-format nil)))) + +;; Rules to control buffer's group rules. +(defvar awesome-tab-groups-hash (make-hash-table :test 'equal)) +(defvar awesome-tab-hide-hash (make-hash-table :test 'equal)) + +(defun awesome-tab-project-name () + (let ((project-name (cdr (project-current)))) + (if project-name + (format "Project: %s" (expand-file-name project-name)) + awesome-tab-common-group-name))) + +(defun awesome-tab-get-group-name (buf) + (let ((group-name (gethash buf awesome-tab-groups-hash))) + ;; Return group name cache if it exists for improve performance. + (if group-name + group-name + ;; Otherwise try get group name with `project-current'. + ;; `project-current' is very slow, it will slow down Emacs if you call it when switch buffer. + (with-current-buffer buf + (let ((project-name (awesome-tab-project-name))) + (puthash buf project-name awesome-tab-groups-hash) + project-name))))) + +(defun awesome-tab-buffer-groups () + "`awesome-tab-buffer-groups' control buffers' group rules. + +Group awesome-tab with mode if buffer is derived from `eshell-mode' `emacs-lisp-mode' `dired-mode' `org-mode' `magit-mode'. +All buffer name start with * will group to \"Emacs\". +Other buffer group by `awesome-tab-get-group-name' with project name." + (list + (cond + ((or (string-equal "*" (substring (buffer-name) 0 1)) + (memq major-mode '(magit-process-mode + magit-status-mode + magit-diff-mode + magit-log-mode + magit-file-mode + magit-blob-mode + magit-blame-mode + ))) + "Emacs") + ((derived-mode-p 'eshell-mode) + "EShell") + ((derived-mode-p 'emacs-lisp-mode) + "Elisp") + ((derived-mode-p 'dired-mode) + "Dired") + ((memq major-mode '(org-mode org-agenda-mode diary-mode)) + "OrgMode") + ((derived-mode-p 'eaf-mode) + "EAF") + (t + (awesome-tab-get-group-name (current-buffer)))))) + +;; Helm source for switching group in helm. +(defvar helm-source-awesome-tab-group nil) + +(defun awesome-tab-build-helm-source () + (interactive) + (setq helm-source-awesome-tab-group + (when (ignore-errors (require 'helm)) + (helm-build-sync-source "Awesome-Tab Group" + :candidates #'awesome-tab-get-groups + :action '(("Switch to group" . awesome-tab-switch-group)))))) + +;;;###autoload +(defun awesome-tab-counsel-switch-group () + "Switch group of awesome-tab." + (interactive) + (when (ignore-errors (require 'ivy)) + (ivy-read + "Awesome-Tab Groups:" + (awesome-tab-get-groups) + :action #'awesome-tab-switch-group + :caller 'awesome-tab-counsel-switch-group))) + +(defun awesome-tab-hide-tab (x) + (let ((name (format "%s" x))) + (or + ;; Current window is not dedicated window. + (window-dedicated-p (selected-window)) + + ;; Buffer name not match below blacklist. + (string-prefix-p "*epc" name) + (string-prefix-p "*helm" name) + (string-prefix-p "*Compile-Log*" name) + (string-prefix-p "*lsp" name) + (string-prefix-p "*flycheck" name) + + ;; Is not magit buffer. + (and (string-prefix-p "magit" name) + (not (file-name-extension name))) + ))) + +(defun awesome-tab-hide-tab-cached (buf) + (let ((hide (gethash buf awesome-tab-hide-hash 'not-found))) + (when (eq hide 'not-found) + (setq hide (funcall awesome-tab-hide-tab-function buf)) + (puthash buf hide awesome-tab-hide-hash)) + hide)) + +(defvar awesome-tab-last-focus-buffer nil + "The last focus buffer.") + +(defvar awesome-tab-last-focus-buffer-group nil + "The group name of last focus buffer.") + +(defun awesome-tab-remove-nth-element (nth list) + (if (zerop nth) (cdr list) + (let ((last (nthcdr (1- nth) list))) + (setcdr last (cddr last)) + list))) + +(defun awesome-tab-insert-after (list aft-el el) + "Insert EL after AFT-EL in LIST." + (push el (cdr (member aft-el list))) + list) + +(defun awesome-tab-insert-before (list bef-el el) + "Insert EL before BEF-EL in LIST." + (nreverse (awesome-tab-insert-after (nreverse list) bef-el el))) + +(advice-add 'load-theme :around #'awesome-tab-load-theme) +(defun awesome-tab-load-theme (orig-fun &optional arg &rest args) + "Update tab after execute `load-theme'." + (apply orig-fun arg args) + (awesome-tab-refresh-display)) + +(provide 'awesome-tab) + +;;; awesome-tab.el ends here diff --git a/.emacs.d/emacs-custom.el b/.emacs.d/emacs-custom.el new file mode 100644 index 0000000..644b8dd --- /dev/null +++ b/.emacs.d/emacs-custom.el @@ -0,0 +1,14 @@ +(custom-set-variables + ;; custom-set-variables was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(package-selected-packages + (quote + (vscode-dark-plus-theme use-package switch-window prettier markdown-mode magit impatient-mode dracula-theme auto-package-update)))) +(custom-set-faces + ;; custom-set-faces was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + ) diff --git a/.emacs.d/emacs-livedown b/.emacs.d/emacs-livedown new file mode 160000 index 0000000..044485a --- /dev/null +++ b/.emacs.d/emacs-livedown @@ -0,0 +1 @@ +Subproject commit 044485afe844073a0e78495a32dbf549e10b89f0 diff --git a/.emacs.d/init.el b/.emacs.d/init.el new file mode 100644 index 0000000..4534252 --- /dev/null +++ b/.emacs.d/init.el @@ -0,0 +1,192 @@ +; Packages + +;; package archives +(require 'package) +(setq package-enable-at-startup nil) +(setq package-archives + '( + ("ELPA" . "http://tromey.com/elpa/") + ("gnu" . "http://elpa.gnu.org/packages/") + ("melpa" . "https://melpa.org/packages/") + ("ORG" . "https://orgmode.org/elpa/") + ) + ) +(package-initialize) + +;; install use-package +(unless (package-installed-p 'use-package) + (package-refresh-contents) + (package-install 'use-package) + ) + +;; Set path to store "custom-set" +(setq custom-file "~/.emacs.d/emacs-custom.el") + +;; Enable awesome-tab-mode +(add-to-list 'load-path (expand-file-name "~/.emacs.d/plugins")) +(require 'awesome-tab) +(awesome-tab-mode t) + +(use-package awesome-tab + :load-path "~/.emacs.d/plugins" + :config + (awesome-tab-mode t)) +(awesome-tab-mode t) + +;; Theme +(use-package dracula-theme + :ensure t + :config + (load-theme 'dracula t)) + +;; Magit +(use-package magit + :ensure t + :config + ) + +(global-set-key (kbd "C-x g") 'magit-status) + +;; Auto enable markdown into html previewOB +;(use-package auto-package-update +; :ensure t +; :config +; (setq auto-package-update-interval 5 +; auto-package-update-delete-old-verions t) +; (auto-package-update-maybe) +; ) + + +;(use-package impatient-mode +; :ensure t +; :mode +; ( +; ("\\.md\\'" . impatient-mode) +; ) +; :hook +; ( +; (impatient-mode . html-mode) +; ) +; :config +; (add-hook 'html-mode-hook +; (lambda () +; (unless (get-process "httpd") +; (markdown-mode) +; (message "starting httpd server...") +; (httpd-start) +; ) +; (impatient-mode) +; (imp-set-user-filter 'markdown-html) +; (imp-visit-buffer) +; ) +; ) +; ) + + +;(defun markdown-html (buffer) +; (princ (with-current-buffer buffer +; (format "Impatient Markdown %s " (buffer-substring-no-properties (point-min) (point-max)))) +; (current-buffer))) + +; Livedown +; git clone https://github.com/shime/emacs-livedown.git ~/.emacs.d/emacs-livedown +; sudo npm install -g livedown +(add-to-list 'load-path (expand-file-name "~/.emacs.d/emacs-livedown")) +(require 'livedown) + +(custom-set-variables + '(livedown-autostart nil) ; automatically open preview when opening markdown files + '(livedown-open t) ; automatically open the browser window + '(livedown-port 1337) ; port for livedown server + '(livedown-browser nil)) ; browser to use +(global-set-key (kbd "C-M-m") 'livedown-preview) + +;; Mew + (autoload 'mew "mew" nil t) + (autoload 'mew-send "mew" nil t) + ;; Optional setup (Read Mail menu for Emacs 21): + (if (boundp 'read-mail-command) + (setq read-mail-command 'mew)) + ;; Optional setup (e.g. C-xm for sending a message): + (autoload 'mew-user-agent-compose "mew" nil t) + (if (boundp 'mail-user-agent) + (setq mail-user-agent 'mew-user-agent)) + (if (fboundp 'define-mail-user-agent) + (define-mail-user-agent + 'mew-user-agent + 'mew-user-agent-compose + 'mew-draft-send-message + 'mew-draft-kill + 'mew-send-hook)) + + +;;; --- Look & Feel --- + +;; no toolbar: +(tool-bar-mode -1) + +;; line numbers: +(global-display-line-numbers-mode 1) + +;; scrolling: +(setq scroll-conservatively 100) + +;; no "bell" (audible notification): +(setq ring-bell-function 'ignore) + +;; highlight: +(global-hl-line-mode 1) + +;; auto reloading (reverting) buffers +(global-auto-revert-mode 1) + +;; disable lock files: +(setq create-lockfiles nil) + +;; disable autosave: +(setq auto-save-default nil) + +;; disable backups: +(setq make-backup-files nil) + +;; Pass "y or n" instead of "yes or no" +(defalias 'yes-or-no-p 'y-or-n-p) + +;; Highlight parens +(show-paren-mode 1) + +;; Candy +(global-prettify-symbols-mode 1) + +;; Modeline +(column-number-mode 1) +(size-indication-mode 1) + +;; Horizontal splitting +(defun split-and-follow-horizontally () + (interactive) + (split-window-below) + (balance-windows) + (other-window 1) + ) +(global-set-key (kbd "C-x 2") 'split-and-follow-horizontally) + +;; Vertical splitting +(defun split-and-follow-vertically () + (interactive) + (split-window-right) + (balance-windows) + (other-window 1) + ) +(global-set-key (kbd "C-x 3") 'split-and-follow-vertically) + +;; Kill & remove split +(defun kill-and-remove-split () + "Kill and remove split." + (interactive) + (kill-buffer) + (delete-window) + (balance-windows) + (other-window 1) + ) +(global-set-key (kbd "C-x x") 'kill-and-remove-split)