diff -Nru ace-window-0.9.0/ace-window.el ace-window-0.10.0/ace-window.el --- ace-window-0.9.0/ace-window.el 2015-05-12 12:05:15.000000000 +0000 +++ ace-window-0.10.0/ace-window.el 2020-03-11 10:25:14.000000000 +0000 @@ -1,12 +1,12 @@ ;;; ace-window.el --- Quickly switch windows. -*- lexical-binding: t -*- -;; Copyright (C) 2015 Free Software Foundation, Inc. +;; Copyright (C) 2015-2020 Free Software Foundation, Inc. ;; Author: Oleh Krehel ;; Maintainer: Oleh Krehel ;; URL: https://github.com/abo-abo/ace-window -;; Version: 0.8.1 -;; Package-Requires: ((avy "0.2.0")) +;; Version: 0.10.0 +;; Package-Requires: ((avy "0.5.0")) ;; Keywords: window, location ;; This file is part of GNU Emacs. @@ -26,35 +26,37 @@ ;;; Commentary: ;; -;; The main function, `ace-window' is meant to replace `other-window'. -;; In fact, when there are only two windows present, `other-window' is -;; called. If there are more, each window will have its first -;; character highlighted. Pressing that character will switch to that -;; window. +;; The main function, `ace-window' is meant to replace `other-window' +;; by assigning each window a short, unique label. When there are only +;; two windows present, `other-window' is called (unless +;; aw-dispatch-always is set non-nil). If there are more, each +;; window will have its first label character highlighted. Once a +;; unique label is typed, ace-window will switch to that window. ;; ;; To setup this package, just add to your .emacs: ;; -;; (global-set-key (kbd "M-p") 'ace-window) +;; (global-set-key (kbd "M-o") 'ace-window) ;; -;; replacing "M-p" with an appropriate shortcut. +;; replacing "M-o" with an appropriate shortcut. ;; -;; Depending on your window usage patterns, you might want to set +;; By default, ace-window uses numbers for window labels so the window +;; labeling is intuitively ordered. But if you prefer to type keys on +;; your home row for quicker access, use this setting: ;; ;; (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)) ;; -;; This way they are all on the home row, although the intuitive -;; ordering is lost. -;; -;; If you don't want the gray background that makes the red selection -;; characters stand out more, set this: +;; Whenever ace-window prompts for a window selection, it grays out +;; all the window characters, highlighting window labels in red. To +;; disable this behavior, set this: ;; ;; (setq aw-background nil) ;; -;; If you want to know the selection characters ahead of time, you can -;; turn on `ace-window-display-mode'. +;; If you want to know the selection characters ahead of time, turn on +;; `ace-window-display-mode'. ;; ;; When prefixed with one `universal-argument', instead of switching -;; to selected window, the selected window is swapped with current one. +;; to the selected window, the selected window is swapped with the +;; current one. ;; ;; When prefixed with two `universal-argument', the selected window is ;; deleted instead. @@ -62,6 +64,7 @@ ;;; Code: (require 'avy) (require 'ring) +(require 'subr-x) ;;* Customization (defgroup ace-window nil @@ -70,20 +73,36 @@ :prefix "aw-") (defcustom aw-keys '(?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9) - "Keys for selecting window.") + "Keys for selecting window." + :type '(repeat character)) (defcustom aw-scope 'global "The scope used by `ace-window'." :type '(choice + (const :tag "visible frames" visible) (const :tag "global" global) (const :tag "frame" frame))) -(defcustom aw-ignored-buffers '("*Calc Trail*" "*LV*") - "List of buffers to ignore when selecting window." +(defcustom aw-translate-char-function #'identity + "Function to translate user input key into another key. +For example, to make SPC do the same as ?a, use +\(lambda (c) (if (= c 32) ?a c))." + :type '(choice + (const :tag "Off" #'identity) + (const :tag "Ignore Case" #'downcase) + (function :tag "Custom"))) + +(defcustom aw-minibuffer-flag nil + "When non-nil, also display `ace-window-mode' string in the minibuffer when ace-window is active." + :type 'boolean) + +(defcustom aw-ignored-buffers '("*Calc Trail*" " *LV*") + "List of buffers and major-modes to ignore when choosing a window from the window list. +Active only when `aw-ignore-on' is non-nil." :type '(repeat string)) (defcustom aw-ignore-on t - "When t, `ace-window' will ignore `aw-ignored-buffers'. + "When t, `ace-window' will ignore buffers and major-modes in `aw-ignored-buffers'. Use M-0 `ace-window' to toggle this value." :type 'boolean) @@ -92,7 +111,7 @@ :type 'boolean) (defcustom aw-background t - "When t, `ace-window' will dim out all buffers temporarily when used.'." + "When t, `ace-window' will dim out all buffers temporarily when used." :type 'boolean) (defcustom aw-leading-char-style 'char @@ -107,45 +126,131 @@ one or two windows." :type 'boolean) +(defcustom aw-dispatch-when-more-than 2 + "If the number of windows is more than this, activate ace-window-ness." + :type 'integer) + +(defcustom aw-reverse-frame-list nil + "When non-nil `ace-window' will order frames for selection in +the reverse of `frame-list'" + :type 'boolean) + +(defcustom aw-frame-offset '(13 . 23) + "Increase in pixel offset for new ace-window frames relative to the selected frame. +Its value is an (x-offset . y-offset) pair in pixels." + :type '(cons integer integer)) + +(defcustom aw-frame-size nil + "Frame size to make new ace-window frames. +Its value is a (width . height) pair in pixels or nil for the default frame size. +(0 . 0) is special and means make the frame size the same as the last selected frame size." + :type '(cons integer integer)) + +(defcustom aw-char-position 'top-left + "Window positions of the character overlay. +Consider changing this if the overlay tends to overlap with other things." + :type '(choice + (const :tag "top left corner only" 'top-left) + (const :tag "both left corners" 'left))) + +;; Must be defined before `aw-make-frame-char' since its :set function references this. +(defvar aw-dispatch-alist + '((?x aw-delete-window "Delete Window") + (?m aw-swap-window "Swap Windows") + (?M aw-move-window "Move Window") + (?c aw-copy-window "Copy Window") + (?j aw-switch-buffer-in-window "Select Buffer") + (?n aw-flip-window) + (?u aw-switch-buffer-other-window "Switch Buffer Other Window") + (?e aw-execute-command-other-window "Execute Command Other Window") + (?F aw-split-window-fair "Split Fair Window") + (?v aw-split-window-vert "Split Vert Window") + (?b aw-split-window-horz "Split Horz Window") + (?o delete-other-windows "Delete Other Windows") + (?T aw-transpose-frame "Transpose Frame") + ;; ?i ?r ?t are used by hyperbole.el + (?? aw-show-dispatch-help)) + "List of actions for `aw-dispatch-default'. +Each action is a list of either: + (char function description) where function takes a single window argument +or + (char function) where function takes no argument and the description is omitted.") + +(defun aw-set-make-frame-char (option value) + ;; Signal an error if `aw-make-frame-char' is ever set to an invalid + ;; or conflicting value. + (when value + (cond ((not (characterp value)) + (user-error "`aw-make-frame-char' must be a character, not `%s'" value)) + ((memq value aw-keys) + (user-error "`aw-make-frame-char' is `%c'; this conflicts with the same character in `aw-keys'" value)) + ((assq value aw-dispatch-alist) + (user-error "`aw-make-frame-char' is `%c'; this conflicts with the same character in `aw-dispatch-alist'" value)))) + (set option value)) + +(defcustom aw-make-frame-char ?z + "Non-existing ace window label character that triggers creation of a new single-window frame for display." + :set 'aw-set-make-frame-char + :type 'character) + (defface aw-leading-char-face - '((((class color)) (:foreground "red")) - (((background dark)) (:foreground "gray100")) - (((background light)) (:foreground "gray0")) - (t (:foreground "gray100" :underline nil))) + '((((class color)) (:foreground "red")) + (((background dark)) (:foreground "gray100")) + (((background light)) (:foreground "gray0")) + (t (:foreground "gray100" :underline nil))) "Face for each window's leading char.") +(defface aw-minibuffer-leading-char-face + '((t :inherit aw-leading-char-face)) + "Face for minibuffer leading char.") + (defface aw-background-face '((t (:foreground "gray40"))) "Face for whole window background during selection.") (defface aw-mode-line-face - '((t (:inherit mode-line-buffer-id))) + '((t (:inherit mode-line-buffer-id))) "Face used for displaying the ace window key in the mode-line.") +(defface aw-key-face + '((t :inherit font-lock-builtin-face)) + "Face used by `aw-show-dispatch-help'.") + ;;* Implementation (defun aw-ignored-p (window) - "Return t if WINDOW should be ignored." + "Return t if WINDOW should be ignored when choosing from the window list." (or (and aw-ignore-on - (member (buffer-name (window-buffer window)) - aw-ignored-buffers)) + ;; Ignore major-modes and buffer-names in `aw-ignored-buffers'. + (or (memq (buffer-local-value 'major-mode (window-buffer window)) + aw-ignored-buffers) + (member (buffer-name (window-buffer window)) aw-ignored-buffers))) + ;; ignore child frames + (and (fboundp 'frame-parent) (frame-parent (window-frame window))) + ;; Ignore selected window if `aw-ignore-current' is non-nil. (and aw-ignore-current - (equal window (selected-window))))) + (equal window (selected-window))) + ;; When `ignore-window-parameters' is nil, ignore windows whose + ;; `no-other-window’ or `no-delete-other-windows' parameter is non-nil. + (unless ignore-window-parameters + (cl-case this-command + (ace-select-window (window-parameter window 'no-other-window)) + (ace-delete-window (window-parameter window 'no-delete-other-windows)) + (ace-delete-other-windows (window-parameter + window 'no-delete-other-windows)))))) (defun aw-window-list () "Return the list of interesting windows." (sort (cl-remove-if (lambda (w) - (let ((f (window-frame w)) - (b (window-buffer w))) + (let ((f (window-frame w))) (or (not (and (frame-live-p f) (frame-visible-p f))) (string= "initial_terminal" (terminal-name f)) - (aw-ignored-p w) - (with-current-buffer b - (and buffer-read-only - (= 0 (buffer-size b))))))) + (aw-ignored-p w)))) (cl-case aw-scope + (visible + (cl-mapcan #'window-list (visible-frame-list))) (global (cl-mapcan #'window-list (frame-list))) (frame @@ -165,6 +270,18 @@ (nconc minor-mode-alist (list '(ace-window-mode ace-window-mode)))) +(defvar aw-empty-buffers-list nil + "Store the read-only empty buffers which had to be modified. +Modify them back eventually.") + +(defvar aw--windows-hscroll nil + "List of (window . hscroll-columns) items, each listing a window whose + horizontal scroll will be restored upon ace-window action completion.") + +(defvar aw--windows-points nil + "List of (window . point) items. The point position had to be + moved in order to display the overlay.") + (defun aw--done () "Clean up mode line and overlays." ;; mode line @@ -172,41 +289,123 @@ ;; background (mapc #'delete-overlay aw-overlays-back) (setq aw-overlays-back nil) - (avy--remove-leading-chars)) + (avy--remove-leading-chars) + (dolist (b aw-empty-buffers-list) + (with-current-buffer b + (when (string= (buffer-string) " ") + (let ((inhibit-read-only t)) + (delete-region (point-min) (point-max)))))) + (setq aw-empty-buffers-list nil) + (aw--restore-windows-hscroll) + (let (c) + (while (setq c (pop aw--windows-points)) + (with-selected-window (car c) + (goto-char (cdr c)))))) + +(defun aw--restore-windows-hscroll () + "Restore horizontal scroll of windows from `aw--windows-hscroll' list." + (let (wnd hscroll) + (mapc (lambda (wnd-and-hscroll) + (setq wnd (car wnd-and-hscroll) + hscroll (cdr wnd-and-hscroll)) + (when (window-live-p wnd) + (set-window-hscroll wnd hscroll))) + aw--windows-hscroll)) + (setq aw--windows-hscroll nil)) + +(defun aw--overlay-str (wnd pos path) + "Return the replacement text for an overlay in WND at POS, +accessible by typing PATH." + (let ((old-str (or + (ignore-errors + (with-selected-window wnd + (buffer-substring pos (1+ pos)))) + ""))) + (concat + (cl-case aw-leading-char-style + (char + (string (avy--key-to-char (car (last path))))) + (path + (mapconcat + (lambda (x) (string (avy--key-to-char x))) + (reverse path) + "")) + (t + (error "Bad `aw-leading-char-style': %S" + aw-leading-char-style))) + (cond ((string-equal old-str "\t") + (make-string (1- tab-width) ?\ )) + ((string-equal old-str "\n") + "\n") + (t + (make-string + (max 0 (1- (string-width old-str))) + ?\ )))))) + +(defun aw--point-visible-p () + "Return non-nil if point is visible in the selected window. +Return nil when horizontal scrolling has moved it off screen." + (and (>= (- (current-column) (window-hscroll)) 0) + (< (- (current-column) (window-hscroll)) + (window-width)))) (defun aw--lead-overlay (path leaf) "Create an overlay using PATH at LEAF. LEAF is (PT . WND)." - (let* ((pt (car leaf)) - (wnd (cdr leaf)) - (ol (make-overlay pt (1+ pt) (window-buffer wnd))) - (old-str (or - (ignore-errors - (with-selected-window wnd - (buffer-substring pt (1+ pt)))) - "")) - (new-str - (concat - (cl-case aw-leading-char-style - (char - (apply #'string (last path))) - (path - (apply #'string (reverse path))) - (t - (error "Bad `aw-leading-char-style': %S" - aw-leading-char-style))) - (cond ((string-equal old-str "\t") - (make-string (1- tab-width) ?\ )) - ((string-equal old-str "\n") - "\n") - (t - (make-string - (max 0 (1- (string-width old-str))) - ?\ )))))) - (overlay-put ol 'face 'aw-leading-char-face) - (overlay-put ol 'window wnd) - (overlay-put ol 'display new-str) - (push ol avy--overlays-lead))) + ;; Properly adds overlay in visible region of most windows except for any one + ;; receiving output while this function is executing, since that moves point, + ;; potentially shifting the added overlay outside the window's visible region. + (let ((wnd (cdr leaf)) + ;; Prevent temporary movement of point from scrolling any window. + (scroll-margin 0)) + (with-selected-window wnd + (when (= 0 (buffer-size)) + (push (current-buffer) aw-empty-buffers-list) + (let ((inhibit-read-only t)) + (insert " "))) + ;; If point is not visible due to horizontal scrolling of the + ;; window, this next expression temporarily scrolls the window + ;; right until point is visible, so that the leading-char can be + ;; seen when it is inserted. When ace-window's action finishes, + ;; the horizontal scroll is restored by (aw--done). + (while (and (not (aw--point-visible-p)) + (not (zerop (window-hscroll))) + (progn (push (cons (selected-window) (window-hscroll)) aw--windows-hscroll) t) + (not (zerop (scroll-right))))) + (let* ((ws (window-start)) + (prev nil) + (vertical-pos (if (eq aw-char-position 'left) -1 0)) + (horizontal-pos (if (zerop (window-hscroll)) 0 (1+ (window-hscroll)))) + (old-pt (point)) + (pt + (progn + ;; If leading-char is to be displayed at the top-left, move + ;; to the first visible line in the window, otherwise, move + ;; to the last visible line. + (move-to-window-line vertical-pos) + (move-to-column horizontal-pos) + ;; Find a nearby point that is not at the end-of-line but + ;; is visible so have space for the overlay. + (setq prev (1- (point))) + (while (and (>= prev ws) (/= prev (point)) (eolp)) + (setq prev (point)) + (unless (bobp) + (line-move -1 t) + (move-to-column horizontal-pos))) + (recenter vertical-pos) + (point))) + (ol (make-overlay pt (1+ pt) (window-buffer wnd)))) + (if (= (aw--face-rel-height) 1) + (goto-char old-pt) + (when (/= pt old-pt) + (goto-char (+ pt 1)) + (push (cons wnd old-pt) aw--windows-points))) + (overlay-put ol 'display (aw--overlay-str wnd pt path)) + (if (window-minibuffer-p wnd) + (overlay-put ol 'face 'aw-minibuffer-leading-char-face) + (overlay-put ol 'face 'aw-leading-char-face)) + (overlay-put ol 'window wnd) + (push ol avy--overlays-lead))))) (defun aw--make-backgrounds (wnd-list) "Create a dim background overlay for each window on WND-LIST." @@ -221,10 +420,6 @@ ol)) wnd-list)))) -(define-obsolete-variable-alias - 'aw-flip-keys 'aw--flip-keys "0.1.0" - "Use `aw-dispatch-alist' instead.") - (defvar aw-dispatch-function 'aw-dispatch-default "Function to call when a character not in `aw-keys' is pressed.") @@ -234,28 +429,98 @@ (defun aw-set-mode-line (str) "Set mode line indicator to STR." (setq ace-window-mode str) + (when (and aw-minibuffer-flag ace-window-mode) + (message "%s" (string-trim-left str))) (force-mode-line-update)) -(defvar aw-dispatch-alist - '((?x aw-delete-window " Ace - Delete Window") - (?m aw-swap-window " Ace - Swap Window") - (?n aw-flip-window) - (?v aw-split-window-vert " Ace - Split Vert Window") - (?b aw-split-window-horz " Ace - Split Horz Window") - (?i delete-other-windows " Ace - Maximize Window") - (?o delete-other-windows)) - "List of actions for `aw-dispatch-default'.") +(defun aw--dispatch-action (char) + "Return item from `aw-dispatch-alist' matching CHAR." + (assoc char aw-dispatch-alist)) + +(defun aw-make-frame () + "Make a new Emacs frame using the values of `aw-frame-size' and `aw-frame-offset'." + (make-frame + (delq nil + (list + ;; This first parameter is important because an + ;; aw-dispatch-alist command may not want to leave this + ;; frame with input focus. If it is given focus, the + ;; command may not be able to return focus to a different + ;; frame since this is done asynchronously by the window + ;; manager. + '(no-focus-on-map . t) + (when aw-frame-size + (cons 'width + (if (zerop (car aw-frame-size)) + (frame-width) + (car aw-frame-size)))) + (when aw-frame-size + (cons 'height + (if (zerop (cdr aw-frame-size)) + (frame-height) + (car aw-frame-size)))) + (cons 'left (+ (car aw-frame-offset) + (car (frame-position)))) + (cons 'top (+ (cdr aw-frame-offset) + (cdr (frame-position)))))))) + +(defun aw-use-frame (window) + "Create a new frame using the contents of WINDOW. + +The new frame is set to the same size as the previous frame, offset by +`aw-frame-offset' (x . y) pixels." + (aw-switch-to-window window) + (aw-make-frame)) + +(defun aw-clean-up-avy-current-path () + "Edit `avy-current-path' so only window label characters remain." + ;; Remove any possible ace-window command char that may + ;; precede the last specified window label, so + ;; functions can use `avy-current-path' as the chosen + ;; window label. + (when (and (> (length avy-current-path) 0) + (assq (aref avy-current-path 0) aw-dispatch-alist)) + (setq avy-current-path (substring avy-current-path 1)))) (defun aw-dispatch-default (char) "Perform an action depending on CHAR." - (let ((val (cdr (assoc char aw-dispatch-alist)))) - (if val - (if (and (car val) (cadr val)) - (prog1 (setq aw-action (car val)) - (aw-set-mode-line (cadr val))) - (funcall (car val)) - (throw 'done 'exit)) - (avy-handler-default char)))) + (cond ((and (fboundp 'avy-mouse-event-window) + (avy-mouse-event-window char))) + ((= char (aref (kbd "C-g") 0)) + (throw 'done 'exit)) + ((and aw-make-frame-char (= char aw-make-frame-char)) + ;; Make a new frame and perform any action on its window. + (let ((start-win (selected-window)) + (end-win (frame-selected-window (aw-make-frame)))) + (if aw-action + ;; Action must be called from the start-win. The action + ;; determines which window to leave selected. + (progn (select-frame-set-input-focus (window-frame start-win)) + (funcall aw-action end-win)) + ;; Select end-win when no action + (aw-switch-to-window end-win))) + (throw 'done 'exit)) + (t + (let ((action (aw--dispatch-action char))) + (if action + (cl-destructuring-bind (_key fn &optional description) action + (if (and fn description) + (prog1 (setq aw-action fn) + (aw-set-mode-line (format " Ace - %s" description))) + (if (commandp fn) + (call-interactively fn) + (funcall fn)) + (throw 'done 'exit))) + (aw-clean-up-avy-current-path) + ;; Prevent any char from triggering an avy dispatch command. + (let ((avy-dispatch-alist)) + (avy-handler-default char))))))) + +(defcustom aw-display-mode-overlay t + "When nil, don't display overlays. Rely on the mode line instead." + :type 'boolean) + +(defvar ace-window-display-mode) (defun aw-select (mode-line &optional action) "Return a selected other window. @@ -263,6 +528,7 @@ (setq aw-action action) (let ((start-window (selected-window)) (next-window-scope (cl-case aw-scope + ('visible 'visible) ('global 'visible) ('frame 'frame))) (wnd-list (aw-window-list)) @@ -278,19 +544,19 @@ (when (eq aw-action 'exit) (setq aw-action nil))) (or (car wnd-list) start-window)) - ((and (= (length wnd-list) 2) (not aw-dispatch-always)) + ((and (<= (+ (length wnd-list) (if (aw-ignored-p start-window) 1 0)) + aw-dispatch-when-more-than) + (not aw-dispatch-always) + (not aw-ignore-current)) (let ((wnd (next-window nil nil next-window-scope))) - (while (and (aw-ignored-p wnd) + (while (and (or (not (memq wnd wnd-list)) + (aw-ignored-p wnd)) (not (equal wnd start-window))) (setq wnd (next-window wnd nil next-window-scope))) wnd)) (t (let ((candidate-list (mapcar (lambda (wnd) - ;; can't jump if the buffer is empty - (with-current-buffer (window-buffer wnd) - (when (= 0 (buffer-size)) - (insert " "))) (cons (aw-offset wnd) wnd)) wnd-list))) (aw--make-backgrounds wnd-list) @@ -299,8 +565,13 @@ (remove-hook 'post-command-hook 'helm--maybe-update-keymap) (unwind-protect (let* ((avy-handler-function aw-dispatch-function) + (avy-translate-char-function aw-translate-char-function) + (transient-mark-mode nil) (res (avy-read (avy-tree candidate-list aw-keys) - #'aw--lead-overlay + (if (and ace-window-display-mode + (null aw-display-mode-overlay)) + (lambda (_path _leaf)) + #'aw--lead-overlay) #'avy--remove-leading-chars))) (if (eq res 'exit) (setq aw-action nil) @@ -334,18 +605,40 @@ #'aw-swap-window)) ;;;###autoload -(defun ace-maximize-window () - "Ace maximize window." +(defun ace-delete-other-windows () + "Ace delete other windows." (interactive) - (aw-select " Ace - Maximize Window" + (aw-select " Ace - Delete Other Windows" #'delete-other-windows)) ;;;###autoload +(defun ace-display-buffer (buffer alist) + "Make `display-buffer' and `pop-to-buffer' select using `ace-window'. +See sample config for `display-buffer-base-action' and `display-buffer-alist': +https://github.com/abo-abo/ace-window/wiki/display-buffer." + (let* ((aw-ignore-current (cdr (assq 'inhibit-same-window alist))) + (rf (cdr (assq 'reusable-frames alist))) + (aw-scope (cl-case rf + ((nil) 'frame) + (visible 'visible) + ((0 t) 'global)))) + (unless (or (<= (length (aw-window-list)) 1) + (not aw-scope)) + (window--display-buffer + buffer (aw-select "Ace - Display Buffer") 'reuse)))) + +(declare-function transpose-frame "ext:transpose-frame") +(defun aw-transpose-frame (w) + "Select any window on frame and `tranpose-frame'." + (transpose-frame (window-frame w))) + +;;;###autoload (defun ace-window (arg) "Select a window. Perform an action based on ARG described below. By default, behaves like extended `other-window'. +See `aw-scope' which extends it to work with frames. Prefixed with one \\[universal-argument], does a swap between the selected window and the current window, so that the selected @@ -355,27 +648,41 @@ Prefixed with two \\[universal-argument]'s, deletes the selected window." (interactive "p") + (setq avy-current-path "") (cl-case arg (0 - (setq aw-ignore-on - (not aw-ignore-on)) - (ace-select-window)) + (let ((aw-ignore-on (not aw-ignore-on))) + (ace-select-window))) (4 (ace-swap-window)) (16 (ace-delete-window)) (t (ace-select-window)))) ;;* Utility +(unless (fboundp 'frame-position) + (defun frame-position (&optional frame) + (let ((pl (frame-parameter frame 'left)) + (pt (frame-parameter frame 'top))) + (when (consp pl) + (setq pl (eval pl))) + (when (consp pt) + (setq pt (eval pt))) + (cons pl pt)))) + (defun aw-window< (wnd1 wnd2) "Return true if WND1 is less than WND2. This is determined by their respective window coordinates. Windows are numbered top down, left to right." - (let ((f1 (window-frame wnd1)) - (f2 (window-frame wnd2)) - (e1 (window-edges wnd1)) - (e2 (window-edges wnd2))) - (cond ((string< (frame-parameter f1 'window-id) - (frame-parameter f2 'window-id)) - t) + (let* ((f1 (window-frame wnd1)) + (f2 (window-frame wnd2)) + (e1 (window-edges wnd1)) + (e2 (window-edges wnd2)) + (p1 (frame-position f1)) + (p2 (frame-position f2)) + (nl (or (null (car p1)) (null (car p2))))) + (cond ((and (not nl) (< (car p1) (car p2))) + (not aw-reverse-frame-list)) + ((and (not nl) (> (car p1) (car p2))) + aw-reverse-frame-list) ((< (car e1) (car e2)) t) ((> (car e1) (car e2)) @@ -412,13 +719,12 @@ (defun aw-switch-to-window (window) "Switch to the window WINDOW." (let ((frame (window-frame window))) + (aw--push-window (selected-window)) (when (and (frame-live-p frame) (not (eq frame (selected-frame)))) (select-frame-set-input-focus frame)) (if (window-live-p window) - (progn - (aw--push-window (selected-window)) - (select-window window)) + (select-window window) (error "Got a dead window %S" window)))) (defun aw-flip-window () @@ -426,8 +732,28 @@ (interactive) (aw-switch-to-window (aw--pop-window))) -(defun aw-delete-window (window) - "Delete window WINDOW." +(defun aw-show-dispatch-help () + "Display action shortucts in echo area." + (interactive) + (message "%s" (mapconcat + (lambda (action) + (cl-destructuring-bind (key fn &optional description) action + (format "%s: %s" + (propertize + (char-to-string key) + 'face 'aw-key-face) + (or description fn)))) + aw-dispatch-alist + "\n")) + ;; Prevent this from replacing any help display + ;; in the minibuffer. + (let (aw-minibuffer-flag) + (mapc #'delete-overlay aw-overlays-back) + (call-interactively 'ace-window))) + +(defun aw-delete-window (window &optional kill-buffer) + "Delete window WINDOW. +When KILL-BUFFER is non-nil, also kill the buffer." (let ((frame (window-frame window))) (when (and (frame-live-p frame) (not (eq frame (selected-frame)))) @@ -435,9 +761,31 @@ (if (= 1 (length (window-list))) (delete-frame frame) (if (window-live-p window) - (delete-window window) + (let ((buffer (window-buffer window))) + (delete-window window) + (when kill-buffer + (kill-buffer buffer))) (error "Got a dead window %S" window))))) +(defun aw-switch-buffer-in-window (window) + "Select buffer in WINDOW." + (aw-switch-to-window window) + (aw--switch-buffer)) + +(declare-function ivy-switch-buffer "ext:ivy") + +(defun aw--switch-buffer () + (cond ((bound-and-true-p ivy-mode) + (ivy-switch-buffer)) + ((bound-and-true-p ido-mode) + (ido-switch-buffer)) + (t + (call-interactively 'switch-to-buffer)))) + +(defcustom aw-swap-invert nil + "When non-nil, the other of the two swapped windows gets the point." + :type 'boolean) + (defun aw-swap-window (window) "Swap buffers of current window and WINDOW." (cl-labels ((swap-windows (window1 window2) @@ -455,7 +803,23 @@ (when (and (window-live-p window) (not (eq window this-window))) (aw--push-window this-window) - (swap-windows this-window window))))) + (if aw-swap-invert + (swap-windows window this-window) + (swap-windows this-window window)))))) + +(defun aw-move-window (window) + "Move the current buffer to WINDOW. +Switch the current window to the previous buffer." + (let ((buffer (current-buffer))) + (switch-to-buffer (other-buffer)) + (aw-switch-to-window window) + (switch-to-buffer buffer))) + +(defun aw-copy-window (window) + "Copy the current buffer to WINDOW." + (let ((buffer (current-buffer))) + (aw-switch-to-window window) + (switch-to-buffer buffer))) (defun aw-split-window-vert (window) "Split WINDOW vertically." @@ -467,6 +831,50 @@ (select-window window) (split-window-horizontally)) +(defcustom aw-fair-aspect-ratio 2 + "The aspect ratio to aim for when splitting windows. +Sizes are based on the number of characters, not pixels. +Increase to prefer wider windows, or decrease for taller windows." + :type 'number) + +(defun aw-split-window-fair (window) + "Split WINDOW vertically or horizontally, based on its current dimensions. +Modify `aw-fair-aspect-ratio' to tweak behavior." + (let ((w (window-body-width window)) + (h (window-body-height window))) + (if (< (* h aw-fair-aspect-ratio) w) + (aw-split-window-horz window) + (aw-split-window-vert window)))) + +(defun aw-switch-buffer-other-window (window) + "Switch buffer in WINDOW." + (aw-switch-to-window window) + (unwind-protect + (aw--switch-buffer) + (aw-flip-window))) + +(defun aw-execute-command-other-window (window) + "Execute a command in WINDOW." + (aw-switch-to-window window) + (unwind-protect + (funcall + (key-binding + (read-key-sequence + "Enter key sequence: "))) + (aw-flip-window))) + +(defun aw--face-rel-height () + (let ((h (face-attribute 'aw-leading-char-face :height))) + (cond + ((eq h 'unspecified) + 1) + ((floatp h) + (max (floor h) 1)) + ((integerp h) + 1) + (t + (error "unexpected: %s" h))))) + (defun aw-offset (window) "Return point in WINDOW that's closest to top left corner. The point is writable, i.e. it's not part of space after newline." @@ -474,10 +882,15 @@ (beg (window-start window)) (end (window-end window)) (inhibit-field-text-motion t)) - (with-current-buffer - (window-buffer window) + (with-current-buffer (window-buffer window) (save-excursion (goto-char beg) + (forward-line (1- + (min + (count-lines + (point) + (point-max)) + (aw--face-rel-height)))) (while (and (< (point) end) (< (- (line-end-position) (line-beginning-position)) @@ -485,10 +898,14 @@ (forward-line)) (+ (point) h))))) +(defun aw--after-make-frame (f) + (aw-update) + (make-frame-visible f)) + ;;* Mode line ;;;###autoload (define-minor-mode ace-window-display-mode - "Minor mode for showing the ace window key in the mode line." + "Minor mode for showing the ace window key in the mode line." :global t (if ace-window-display-mode (progn @@ -501,24 +918,34 @@ 'ace-window-display-mode (default-value 'mode-line-format)))) (force-mode-line-update t) - (add-hook 'window-configuration-change-hook 'aw-update)) + (add-hook 'window-configuration-change-hook 'aw-update) + ;; Add at the end so does not precede select-frame call. + (add-hook 'after-make-frame-functions #'aw--after-make-frame t)) (set-default 'mode-line-format (assq-delete-all 'ace-window-display-mode (default-value 'mode-line-format))) - (remove-hook 'window-configuration-change-hook 'aw-update))) + (remove-hook 'window-configuration-change-hook 'aw-update) + (remove-hook 'after-make-frame-functions 'aw--after-make-frame))) (defun aw-update () - "Update ace-window-path window parameter for all windows." - (avy-traverse - (avy-tree (aw-window-list) aw-keys) - (lambda (path leaf) - (set-window-parameter - leaf 'ace-window-path - (propertize - (apply #'string (reverse path)) - 'face 'aw-mode-line-face))))) + "Update ace-window-path window parameter for all windows. + +Ensure all windows are labeled so the user can select a specific +one, even from the set of windows typically ignored when making a +window list." + (let ((aw-ignore-on) + (aw-ignore-current) + (ignore-window-parameters t)) + (avy-traverse + (avy-tree (aw-window-list) aw-keys) + (lambda (path leaf) + (set-window-parameter + leaf 'ace-window-path + (propertize + (apply #'string (reverse path)) + 'face 'aw-mode-line-face)))))) (provide 'ace-window) diff -Nru ace-window-0.9.0/Cask ace-window-0.10.0/Cask --- ace-window-0.9.0/Cask 2015-05-12 12:05:15.000000000 +0000 +++ ace-window-0.10.0/Cask 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -(source gnu) -(source melpa) - -(package-file "ace-window.el") - -(development - (depends-on "avy")) - diff -Nru ace-window-0.9.0/debian/changelog ace-window-0.10.0/debian/changelog --- ace-window-0.9.0/debian/changelog 2019-08-25 16:09:19.000000000 +0000 +++ ace-window-0.10.0/debian/changelog 2020-03-12 06:00:58.000000000 +0000 @@ -1,3 +1,22 @@ +ace-window (0.10.0-1) unstable; urgency=medium + + [ David Krauser ] + * d/control: Update maintainer email address + + [ Lev Lamberov ] + * New upstream version 0.10.0 + * Drop patch to fix version number + * Add patch to clean documentation + * Migrate to dh 12 without d/compat + * d/control: Declare Standards-Version 4.5.0 (no changes needed) + * d/control: Add Rules-Requires-Root: no + * d/control: Drop emacs25 from Enhances + * d/control: Better format of Description + * d/copyright: Update copyright years + * d/rules: Drop unneeded overrides + + -- Lev Lamberov Thu, 12 Mar 2020 11:00:58 +0500 + ace-window (0.9.0-5) unstable; urgency=medium * Team upload. diff -Nru ace-window-0.9.0/debian/compat ace-window-0.10.0/debian/compat --- ace-window-0.9.0/debian/compat 2019-08-25 16:09:19.000000000 +0000 +++ ace-window-0.10.0/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -11 diff -Nru ace-window-0.9.0/debian/control ace-window-0.10.0/debian/control --- ace-window-0.9.0/debian/control 2019-08-25 16:09:19.000000000 +0000 +++ ace-window-0.10.0/debian/control 2020-03-12 06:00:58.000000000 +0000 @@ -1,11 +1,12 @@ Source: ace-window Section: lisp Priority: optional -Maintainer: Debian Emacs addons team +Maintainer: Debian Emacsen team Uploaders: Lev Lamberov -Build-Depends: debhelper (>= 11), +Build-Depends: debhelper-compat (= 12), dh-elpa -Standards-Version: 4.1.4 +Standards-Version: 4.5.0 +Rules-Requires-Root: no Homepage: https://github.com/abo-abo/ace-window Vcs-Browser: https://salsa.debian.org/emacsen-team/ace-window Vcs-Git: https://salsa.debian.org/emacsen-team/ace-window.git @@ -15,10 +16,9 @@ Depends: ${elpa:Depends}, ${misc:Depends} Recommends: emacs (>= 46.0) -Enhances: emacs, - emacs25 +Enhances: emacs Description: selecting a window to switch to - The main function, `ace-window' is meant to replace `other-window'. In fact, - when there are only two windows present, `other-window' is called. If there - are more, each window will have its first character highlighted. Pressing - that character will switch to that window. + The main function, `ace-window' is meant to replace `other-window'. + In fact, when there are only two windows present, `other-window' is + called. If there are more, each window will have its first character + highlighted. Pressing that character will switch to that window. diff -Nru ace-window-0.9.0/debian/copyright ace-window-0.10.0/debian/copyright --- ace-window-0.9.0/debian/copyright 2019-08-25 16:09:19.000000000 +0000 +++ ace-window-0.10.0/debian/copyright 2020-03-12 06:00:58.000000000 +0000 @@ -4,11 +4,11 @@ Upstream-Contact: Oleh Krehel Files: * -Copyright: (C) 2015 Free Software Foundation, Inc. +Copyright: (C) 2015-2020 Free Software Foundation, Inc. License: GPL-3+ Files: debian/* -Copyright: (C) 2016-2018 Lev Lamberov +Copyright: (C) 2016-2020 Lev Lamberov License: GPL-3+ License: GPL-3+ diff -Nru ace-window-0.9.0/debian/patches/0001-clean-documentation.diff ace-window-0.10.0/debian/patches/0001-clean-documentation.diff --- ace-window-0.9.0/debian/patches/0001-clean-documentation.diff 1970-01-01 00:00:00.000000000 +0000 +++ ace-window-0.10.0/debian/patches/0001-clean-documentation.diff 2020-03-12 06:00:58.000000000 +0000 @@ -0,0 +1,17 @@ +From: Lev Lamberov +Subject: Remove badges from README file + +This patch removes badges from README file. These badges are loaded +from an external web site. + +--- a/README.md ++++ b/README.md +@@ -1,8 +1,5 @@ + # ace-window + +-[![MELPA](https://melpa.org/packages/ace-window-badge.svg)](https://melpa.org/#/ace-window) +-[![MELPA Stable](https://stable.melpa.org/packages/ace-window-badge.svg)](https://stable.melpa.org/#/ace-window) +- + **GNU Emacs package for selecting a window to switch to** + + ## What and why diff -Nru ace-window-0.9.0/debian/patches/fix-version.diff ace-window-0.10.0/debian/patches/fix-version.diff --- ace-window-0.9.0/debian/patches/fix-version.diff 2019-08-25 16:09:19.000000000 +0000 +++ ace-window-0.10.0/debian/patches/fix-version.diff 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -From: Lev Lamberov -Subject: Fix version number - -This patch fixes version number, since upstream forgot to change it in time. - ---- a/ace-window.el -+++ b/ace-window.el -@@ -5,7 +5,7 @@ - ;; Author: Oleh Krehel - ;; Maintainer: Oleh Krehel - ;; URL: https://github.com/abo-abo/ace-window --;; Version: 0.8.1 -+;; Version: 0.9.0 - ;; Package-Requires: ((avy "0.2.0")) - ;; Keywords: window, location - diff -Nru ace-window-0.9.0/debian/patches/series ace-window-0.10.0/debian/patches/series --- ace-window-0.9.0/debian/patches/series 2019-08-25 16:09:19.000000000 +0000 +++ ace-window-0.10.0/debian/patches/series 2020-03-12 06:00:58.000000000 +0000 @@ -1 +1 @@ -fix-version.diff +0001-clean-documentation.diff diff -Nru ace-window-0.9.0/debian/rules ace-window-0.10.0/debian/rules --- ace-window-0.9.0/debian/rules 2019-08-25 16:09:19.000000000 +0000 +++ ace-window-0.10.0/debian/rules 2020-03-12 06:00:58.000000000 +0000 @@ -3,9 +3,6 @@ %: dh $@ --with elpa -override_dh_auto_build: - @echo skipping upstream build - override_dh_elpa_test: @echo skipping upstream tests diff -Nru ace-window-0.9.0/Makefile ace-window-0.10.0/Makefile --- ace-window-0.9.0/Makefile 2015-05-12 12:05:15.000000000 +0000 +++ ace-window-0.10.0/Makefile 2020-03-11 10:25:14.000000000 +0000 @@ -1,15 +1,15 @@ emacs ?= emacs -CASK = ~/.cask/bin/cask -.PHONY: all clean +update: + $(emacs) -batch -l test/make-update.el -all: compile +compile: clean + $(emacs) -batch -l test/elpa.el -l test/make-compile.el -cask: - $(shell EMACS=$(emacs) $(CASK) --verbose --debug) - -compile: - $(CASK) exec $(emacs) -batch --eval "(byte-compile-file \"ace-window.el\")" +plain: + $(emacs) -Q -l test/elpa.el -l test/make-plain clean: rm -f *.elc + +.PHONY: update compile clean diff -Nru ace-window-0.9.0/README.md ace-window-0.10.0/README.md --- ace-window-0.9.0/README.md 2015-05-12 12:05:15.000000000 +0000 +++ ace-window-0.10.0/README.md 2020-03-11 10:25:14.000000000 +0000 @@ -1,16 +1,19 @@ # ace-window +[![MELPA](https://melpa.org/packages/ace-window-badge.svg)](https://melpa.org/#/ace-window) +[![MELPA Stable](https://stable.melpa.org/packages/ace-window-badge.svg)](https://stable.melpa.org/#/ace-window) + **GNU Emacs package for selecting a window to switch to** ## What and why -I'm sure you're aware of `other-window` command. While it's great for -two windows, it quickly loses it's value when there are more windows: -you need to call it many times, and since it's not easily predictable, +I'm sure you're aware of the `other-window` command. While it's great +for two windows, it quickly loses its value when there are more windows. +You need to call it many times, and since it's not easily predictable, you have to check each time if you're in the window that you wanted. -Another approach is to use `windmove-left`, `windmove-up` etc. These -are fast and predictable. Their disadvantage is that they need 4 key +Another approach is to use `windmove-left`, `windmove-up`, etc. These +are fast and predictable. Their disadvantage is that they need 4 key bindings. The default ones are shift+arrows, which are hard to reach. This package aims to take the speed and predictability of `windmove` @@ -19,25 +22,35 @@ ## Setup Just assign `ace-window` to a short key binding, as switching windows -is a common task. I suggest M-p, as it's short and not -bound in the default Emacs. +is a common task. I suggest M-o, as it's short and not +bound to anything important in the default Emacs. ## Usage -When there are two windows, `ace-window` will call `other-window`. If -there are more, each window will have its first character highlighted. -Pressing that character will switch to that window. Note that, unlike -`ace-jump-mode`, the point position will not be changed: it's the same -behavior as that of `other-window`. +When there are two windows, `ace-window` will call `other-window` +(unless `aw-dispatch-always` is set non-nil). If there are more, each +window will have the first character of its window label highlighted +at the upper left of the window. Pressing that character will either +switch to that window or filter to the next character needed to select +a specific window. Note that, unlike `ace-jump-mode`, the position of +point will not be changed, i.e. the same behavior as that of +`other-window`. + +A special character defined by `aw-make-frame-char` (default = `z`) +means create a new frame and use its window as the target. The new +frame's location is set relative to the prior selected frame's location +and given by `aw-frame-offset`. The new frame's size is given by +`aw-frame-size`. See their documentation strings for more information. -The windows are ordered top-down, left-to-right. This means that if -you remember your window layouts, you can switch windows without even +The windows are ordered top-down, left-to-right. This means that if you +remember your window layouts, you can switch windows without even looking at the leading char. For instance, the top left window will -always be `1`. +always be `1` (or `a` if you use letters for window characters). `ace-window` works across multiple frames, as you can see from the [in-action gif](http://oremacs.com/download/ace-window.gif). + ## Swap and delete window - You can swap windows by calling `ace-window` with a prefix argument C-u. @@ -49,24 +62,31 @@ You can also start by calling `ace-window` and then decide to switch the action to `delete` or `swap` etc. By default the bindings are: - x - delete window -- m - swap (move) window +- m - swap windows +- M - move window +- c - copy window +- j - select buffer +- n - select the previous window +- u - select buffer in the other window +- c - split window fairly, either vertically or horizontally - v - split window vertically - b - split window horizontally -- n - select the previous window -- i - maximize window (select which window) - o - maximize current window +- ? - show these command bindings -In order for it to work, these keys *must not* be in `aw-keys` and you have to have `aw-dispatch-always` set to `t`. +For proper operation, these keys *must not* be in `aw-keys`. Additionally, +if you want these keys to work with fewer than three windows, you need to +have `aw-dispatch-always` set to `t`. ## Customization Aside from binding `ace-window`: - (global-set-key (kbd "M-p") 'ace-window) + (global-set-key (kbd "M-o") 'ace-window) -maybe you'd like the following customizations: +the following customizations are available: ### `aw-keys` -`aw-keys` - the sequence of leading characters for each window: +`aw-keys` - the list of initial characters used in window labels: (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)) @@ -75,14 +95,14 @@ ### `aw-scope` The default one is `global`, which means that `ace-window` will work -across frames. If you set this to `frame`, `ace-window` will offer you -the windows only on current frame. +across frames. If you set this to `frame`, `ace-window` will offer you +only the windows of the current frame. ### `aw-background` By default, `ace-window` temporarily sets a gray background and removes color from available windows in order to make the -window-switching characters more visible. This is the behavior +window-switching characters more visible. This is the behavior inherited from `ace-jump-mode`. This behavior might not be necessary, as you already know the locations @@ -93,28 +113,56 @@ ### `aw-dispatch-always` -When non-nil, `ace-window` will issue a `read-char` event for one window. -This will make `ace-window` act different from `other-window` for one -or two windows. This is useful to be able to change the action midway -and execute other action other than the *jump* default. -By default is set to `nil` +When non-nil, `ace-window` will issue a `read-char` even for one window. +This will make `ace-window` act differently from `other-window` for one +or two windows. This is useful to change the action midway and execute +an action other than the default *jump* action. +By default, this is set to `nil`. ### `aw-dispatch-alist` -This is the list of actions that you can trigger from `ace-window` other than the -*jump* default. -By default is: - - (defvar aw-dispatch-alist - '((?x aw-delete-window " Ace - Delete Window") - (?m aw-swap-window " Ace - Swap Window") - (?n aw-flip-window) - (?v aw-split-window-vert " Ace - Split Vert Window") - (?b aw-split-window-horz " Ace - Split Horz Window") - (?i delete-other-windows " Ace - Maximize Window") - (?o delete-other-windows)) - "List of actions for `aw-dispatch-default'.") - -If the pair key-action is followed by a string, then `ace-window` will be -invoked again to be able to select on which window you want to select the -action. Otherwise the current window is selected. +This is the list of actions you can trigger from `ace-window` other than the +*jump* default. By default it is: + + (defvar aw-dispatch-alist + '((?x aw-delete-window "Delete Window") + (?m aw-swap-window "Swap Windows") + (?M aw-move-window "Move Window") + (?c aw-copy-window "Copy Window") + (?j aw-switch-buffer-in-window "Select Buffer") + (?n aw-flip-window) + (?u aw-switch-buffer-other-window "Switch Buffer Other Window") + (?c aw-split-window-fair "Split Fair Window") + (?v aw-split-window-vert "Split Vert Window") + (?b aw-split-window-horz "Split Horz Window") + (?o delete-other-windows "Delete Other Windows") + (?? aw-show-dispatch-help)) + "List of actions for `aw-dispatch-default'.") + +When using ace-window, if the action character is followed by a string, +then `ace-window` will be invoked again to select the target window for +the action. Otherwise, the current window is selected. + +### `aw-minibuffer-flag` + +When non-nil, also display `ace-window-mode` string in the minibuffer +when `ace-window` is active. This is useful when there are many +side-by-side windows and the `ace-window-mode` string is cutoff in the +minor mode area of the modeline. + +### `aw-ignored-buffers` + +List of buffers and major-modes to ignore when choosing a window from +the window list. Active only when `aw-ignore-on` is non-nil. Windows +displaying these buffers can still be chosen by typing their specific +labels. + +### `aw-ignore-on` + +When t, `ace-window` will ignore buffers and major-modes in +`aw-ignored-buffers`. Use M-0 `ace-window` to toggle this value. + :type 'boolean) + +### `aw-ignore-current` + +When t, `ace-window` will ignore `selected-window'. diff -Nru ace-window-0.9.0/test/elpa.el ace-window-0.10.0/test/elpa.el --- ace-window-0.9.0/test/elpa.el 1970-01-01 00:00:00.000000000 +0000 +++ ace-window-0.10.0/test/elpa.el 2020-03-11 10:25:14.000000000 +0000 @@ -0,0 +1,4 @@ +(setq package-user-dir + (expand-file-name (format "~/.elpa/%s/elpa" emacs-version))) +(package-initialize) +(add-to-list 'load-path default-directory) diff -Nru ace-window-0.9.0/test/make-compile.el ace-window-0.10.0/test/make-compile.el --- ace-window-0.9.0/test/make-compile.el 1970-01-01 00:00:00.000000000 +0000 +++ ace-window-0.10.0/test/make-compile.el 2020-03-11 10:25:14.000000000 +0000 @@ -0,0 +1,3 @@ +(setq files '("ace-window.el")) +(setq byte-compile--use-old-handlers nil) +(mapc #'byte-compile-file files) diff -Nru ace-window-0.9.0/test/make-plain.el ace-window-0.10.0/test/make-plain.el --- ace-window-0.9.0/test/make-plain.el 1970-01-01 00:00:00.000000000 +0000 +++ ace-window-0.10.0/test/make-plain.el 2020-03-11 10:25:14.000000000 +0000 @@ -0,0 +1,2 @@ +(require 'ace-window) +(global-set-key (kbd "M-o") 'ace-window) diff -Nru ace-window-0.9.0/test/make-update.el ace-window-0.10.0/test/make-update.el --- ace-window-0.9.0/test/make-update.el 1970-01-01 00:00:00.000000000 +0000 +++ ace-window-0.10.0/test/make-update.el 2020-03-11 10:25:14.000000000 +0000 @@ -0,0 +1,28 @@ +;;* list of the all dependencies +(defvar dev-packages '(avy)) + +;;* initialize package.el +(setq package-user-dir + (expand-file-name (format "~/.elpa/%s/elpa" emacs-version))) +(message "installing in %s ...\n" package-user-dir) +(package-initialize) +(setq package-archives + '(("melpa" . "https://melpa.org/packages/") + ("gnu" . "http://elpa.gnu.org/packages/"))) +(package-refresh-contents) + +;;* install dependencies +(dolist (package dev-packages) + (unless (package-installed-p package) + (ignore-errors + (package-install package)))) + +;;* upgrade dependencies +(save-window-excursion + (package-list-packages t) + (condition-case nil + (progn + (package-menu-mark-upgrades) + (package-menu-execute t)) + (error + (message "All packages up to date"))))