Working emacs prelude with ox-twbs

clean_emacs
TuDatTr 2018-01-09 04:40:58 +01:00
parent 505d3526b8
commit 3a8d215db7
No known key found for this signature in database
GPG Key ID: 6B2AC5D2CAECE06A
238 changed files with 5631 additions and 60245 deletions

26
emacs/.emacs.d/.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
*~
*.elc
auto-save-list
recentf
savehist
saveplace
eshell
elpa
el-get
semanticdb
url
ede-projects.el
.DS_Store
custom.el
places
.smex-items
savefile/
/prelude-modules.el
projectile-bookmarks.eld
session*
.cask
tramp
/var/pcache
.emacs.desktop
.emacs.desktop.lock
network-security.data

View File

@ -1 +0,0 @@
../.dotfiles/emacs/.emacs.d/.projectile

View File

@ -0,0 +1,3 @@
/elpa
/savefile
/.cask

View File

@ -1 +0,0 @@
../.dotfiles/emacs/.emacs.d/CONTRIBUTING.md

View File

@ -0,0 +1,31 @@
# Contributing
If you discover issues, have ideas for improvements or new features, or
want to contribute a new module, please report them to the
[issue tracker][1] of the repository or submit a pull request. Please,
try to follow these guidelines when you do so.
## Issue reporting
* Check that the issue has not already been reported.
* Check that the issue has not already been fixed in the latest code
(a.k.a. `master`).
* Be clear, concise and precise in your description of the problem.
* Open an issue with a descriptive title and a summary in grammatically correct,
complete sentences.
* Include any relevant code to the issue summary.
## Pull requests
* Read [how to properly contribute to open source projects on Github][2].
* Use a topic branch to easily amend a pull request later, if necessary.
* Write [good commit messages][3].
* Use the same coding conventions as the rest of the project.
* Verify your Emacs Lisp code with `checkdoc` (<kbd>C-c ? d</kbd>).
* Open a [pull request][4] that relates to *only* one subject with a clear title
and description in grammatically correct, complete sentences.
[1]: https://github.com/bbatsov/prelude/issues
[2]: http://gun.io/blog/how-to-github-fork-branch-and-pull-request
[3]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
[4]: https://help.github.com/articles/using-pull-requests

View File

@ -1 +0,0 @@
../.dotfiles/emacs/.emacs.d/README.md

730
emacs/.emacs.d/README.md Normal file
View File

@ -0,0 +1,730 @@
[![License GPL 3][badge-license]](http://www.gnu.org/licenses/gpl-3.0.txt)
[![Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/bbatsov/donate)
[![Patreon](https://img.shields.io/badge/patreon-donate-orange.svg)](https://www.patreon.com/bbatsov)
Emacs Prelude
=============
[![Join the chat at https://gitter.im/bbatsov/prelude](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bbatsov/prelude?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Prelude is an Emacs distribution that aims to enhance the default
Emacs experience. Prelude alters a lot of the default settings,
bundles a plethora of additional packages and adds its own core
library to the mix. The final product offers an easy to use Emacs
configuration for Emacs newcomers and lots of additional power for
Emacs power users.
Prelude is compatible **ONLY with GNU Emacs 24.4+**. In general you're
advised to always run Prelude with the latest Emacs - currently
**25.2**.
You can support the development of Prelude via
[Salt](https://bountysource.com/teams/prelude),
[Patreon](https://www.patreon.com/bbatsov) and
[Liberapay](https://liberapay.com/bbatsov/donate).
[![Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/bbatsov/donate)
[![Patreon](https://img.shields.io/badge/patreon-donate-orange.svg)](https://www.patreon.com/bbatsov)
**Table of Contents**
- [Fast Forward](#fast-forward)
- [Installing Emacs](#installing-emacs)
- [Installation](#installation)
- [Automated](#automated)
- [Via Curl](#via-curl)
- [Via Wget](#via-wget)
- [Manual](#manual)
- [Updating Prelude](#updating-prelude)
- [Manual update](#manual-update)
- [Update all bundled packages](#update-all-bundled-packages)
- [Update Prelude's code](#update-preludes-code)
- [Restart Prelude](#restart-prelude)
- [Automatic update](#automatic-update)
- [Enabling additional modules](#enabling-additional-modules)
- [Running](#running)
- [Getting to know Prelude](#getting-to-know-prelude)
- [Keymap](#keymap)
- [Global](#global)
- [Prelude Mode](#prelude-mode)
- [macOS modifier keys](#macos-modifier-keys)
- [Projectile](#projectile)
- [Helm](#helm)
- [Key-chords](#key-chords)
- [Disabling key-chords](#disabling-key-chords)
- [Automatic package installation](#automatic-package-installation)
- [Color Themes](#color-themes)
- [Personalizing](#personalizing)
- [Disabling whitespace-mode](#disabling-whitespace-mode)
- [Disable flyspell-mode](#disable-flyspell-mode)
- [Caveats & Pitfalls](#caveats--pitfalls)
- [Updating bundled packages](#updating-bundled-packages)
- [Problems with flyspell-mode](#problems-with-flyspell-mode)
- [Ugly colors in the terminal Emacs version](#ugly-colors-in-the-terminal-emacs-version)
- [MELPA error on initial startup](#melpa-error-on-initial-startup)
- [Warnings on arrow navigation in editor buffers](#warnings-on-arrow-navigation-in-editor-buffers)
- [Customized C-a behavior](#customized-c-a-behavior)
- [Poor ido matching performance on large datasets](#poor-ido-matching-performance-on-large-datasets)
- [Windows compatibility](#windows-compatibility)
- [Known issues](#known-issues)
- [Support](#support)
- [Contributors](#contributors)
- [Bugs & Improvements](#bugs--improvements)
## Fast Forward
Assuming you're using an Unix-like OS (`*BSD`, `GNU/Linux`, `macOS`, `Solaris`,
etc), you already have Emacs 24.4+ installed, as well as `git` & `curl` you
can skip the whole manual and just type in your favorite shell the
following command:
```bash
curl -L https://git.io/epre | sh
```
You can now power up your Emacs, sit back and enjoy Prelude,
forgetting about the rest of this manual.
There are two environment variables you can use to control the
source repository and the installation directory. To change the
installation directory:
```bash
export PRELUDE_INSTALL_DIR="$HOME/.emacs.d" && curl -L https://github.com/bbatsov/prelude/raw/master/utils/installer.sh | sh
```
To change the source repository:
```bash
export PRELUDE_URL="https://github.com/yourname/prelude.git" && curl -L https://github.com/bbatsov/prelude/raw/master/utils/installer.sh | sh
```
Note that the installer will back up any existing `.emacs` file or
`.emacs.d` since it will unpack Prelude's code in `.emacs.d`. If
you're doing a manual install make sure you don't have a `.emacs` file
or back up your existing `.emacs.d` directory manually.
Don't forget to adjust your `prelude-modules.el` file once the installation is done.
By default most of the modules that ship with Prelude are not loaded.
## Installing Emacs
Obviously to use the Emacs Prelude you have to install Emacs
first. Have a look at
the
[WikEmacs articles on installing Emacs](http://wikemacs.org/index.php/Installing_Emacs).
## Installation
### Automated
You can install **Emacs Prelude** via the command line with either `curl` or
`wget`. Naturally `git` is also required.
#### Via Curl
If you're using `curl` type the following command:
```bash
curl -L https://github.com/bbatsov/prelude/raw/master/utils/installer.sh | sh
```
#### Via Wget
If you're using `wget` type:
```bash
wget --no-check-certificate https://github.com/bbatsov/prelude/raw/master/utils/installer.sh -O - | sh
```
### Manual
Make sure you do not have any `~/.emacs` file present.
```bash
git clone git://github.com/bbatsov/prelude.git path/to/local/repo
ln -s path/to/local/repo ~/.emacs.d
cd ~/.emacs.d
```
If you are using Windows, you should check what Emacs thinks the `~` directory is by running Emacs and typing `C-x d ~/<RET>`, and then adjust the command appropriately.
## Updating Prelude
### Manual update
The update procedure is fairly straightforward and consists of 3 steps:
#### Update all bundled packages
Just run <kbd>M-x package-list-packages RET U x</kbd>.
#### Update Prelude's code
```bash
cd path/to/prelude/installation
git pull
```
The `path/to/prelude/installation` is usually `~/.emacs.d` (at least
on Unix systems).
#### Restart Prelude
It's generally a good idea to stop Emacs after you do the update. The
next time Prelude starts it will install any new dependencies (if
there are such).
### Automatic update
Simply run <kbd>M-x prelude-update</kbd> from Emacs itself and restart Emacs afterwards.
## Pinning packages
By default, Prelude will install packages from the melpa and gnu package
repositories. Occasionally package integration can break when upgrading packages.
This can be avoided by pinning packages to stable versions in other repositories.
To do so, copy `prelude-pinned-packages.el` from the sample directory to
Prelude's root directory and adjust the [variables](https://www.gnu.org/software/emacs/manual/html_node/emacs/Package-Installation.html)
inside accordingly.
## Enabling additional modules
By default most of the modules that ship with Prelude are not loaded. For more information on the functionality provided by these modules visit the [docs](modules/doc/README.md).
```lisp
;;; Uncomment the modules you'd like to use and restart Prelude afterwards
(require 'prelude-c)
;; (require 'prelude-clojure)
;; (require 'prelude-coffee)
;; (require 'prelude-common-lisp)
;; (require 'prelude-css)
(require 'prelude-emacs-lisp)
(require 'prelude-erc)
;; (require 'prelude-erlang)
;; (require 'prelude-elixir)
;; (require 'prelude-haskell)
(require 'prelude-js)
;; (require 'prelude-latex)
(require 'prelude-lisp)
;; (require 'prelude-mediawiki)
(require 'prelude-org)
(require 'prelude-perl)
;; (require 'prelude-python)
;; (require 'prelude-ruby)
;; (require 'prelude-scala)
(require 'prelude-scheme)
;; (require 'prelude-scss)
;; (require 'prelude-web)
(require 'prelude-xml)
```
You'll need to adjust your `prelude-modules.el` file once the
installation is done. If you are doing a manual install then you first
need to copy the `prelude-modules.el` available in the sample
directory to the root of `path/to/prelude/installation` and then
adjust that one.
After you've uncommented a module you should either restart Emacs or evaluate the module
`require` expression with <kbd>C-x C-e</kbd>.
## Running
Nothing fancy here. Just start Emacs as usual. Personally I run Emacs
in daemon mode:
```bash
emacs --daemon
```
Afterwards I connect to the server with either a terminal or a GUI
client like this:
```bash
emacsclient -t
emacsclient -c
```
You'd probably do well to put a few aliases in your `.zshrc` (or
`.bashrc`):
```bash
alias e='emacsclient -t'
alias ec='emacsclient -c'
alias vim='emacsclient -t'
alias vi='emacsclient -t'
```
The last two aliases are helpful if you're used to editing files from
the command line using `vi(m)`.
You can also open a file with the cursor positioned directly on a specific line:
```bash
emacsclient somefile:1234
```
This will open file 'somefile' and set cursor on line 1234.
## Getting to know Prelude
Certainly the best way to understand how Prelude enhances the default
Emacs experience is to peruse Prelude's source code (which is
obviously written in Emacs Lisp). Understanding the code is not
necessary of course. Prelude includes a `prelude-mode` minor Emacs mode
which collects some of the additional functionality added by
Prelude. It also adds an additional keymap that binds many of those
extensions to keybindings.
### Keymap
#### Global
Keybinding | Description
-------------------|------------------------------------------------------------
<kbd>C-x \\</kbd> | `align-regexp`
<kbd>C-+</kbd> | Increase font size(`text-scale-increase`).
<kbd>C--</kbd> | Decrease font size(`text-scale-decrease`).
<kbd>C-x O</kbd> | Go back to previous window (the inverse of `other-window` (`C-x o`)).
<kbd>C-^</kbd> | Join two lines into one(`crux-top-join-line`).
<kbd>C-x p</kbd> | Start `proced` (manage processes from Emacs; works only in Linux).
<kbd>C-x m</kbd> | Start `eshell`.
<kbd>C-x M-m</kbd> | Start your default shell.
<kbd>C-x C-m</kbd> | Alias for `M-x`.
<kbd>M-X</kbd> | Like `M-x` but limited to commands that are relevant to the active major mode.
<kbd>C-h A</kbd> | Run `apropos` (search in all Emacs symbols).
<kbd>C-h C-m</kbd> | Display key bindings of current major mode and descriptions of every binding.
<kbd>M-/</kbd> | Run `hippie-expand` (a replacement for the default `dabbrev-expand`).
<kbd>C-x C-b</kbd> | Open `ibuffer` (a replacement for the default `buffer-list`).
<kbd>F11</kbd> | Make the window full screen.
<kbd>F12</kbd> | Toggle the Emacs menu bar.
<kbd>C-x g</kbd> | Open Magit's status buffer.
<kbd>C-x M-g</kbd> | Open Magit's popup of popups.
<kbd>M-Z</kbd> | Zap up to char.
<kbd>C-=</kbd> | Run `expand-region` (incremental text selection).
<kbd>C-a</kbd> | Run `crux-move-beginning-of-line`. Read [this](http://emacsredux.com/blog/2013/05/22/smarter-navigation-to-the-beginning-of-a-line/) for details.
#### Prelude Mode
Keybinding | Description
-------------------|------------------------------------------------------------
<kbd>C-c o</kbd> | Open the currently visited file with an external program.
<kbd>C-c i</kbd> | Search for a symbol, only for buffers that contain code
<kbd>C-c g</kbd> | Search in Google for the thing under point (or an interactive query).
<kbd>C-c G</kbd> | Search in GitHub for the thing under point (or an interactive query).
<kbd>C-c y</kbd> | Search in YouTube for the thing under point (or an interactive query).
<kbd>C-c U</kbd> | Search in Duckduckgo for the thing under point (or an interactive query).
<kbd>C-S-RET</kbd> or <kbd>Super-o</kbd> | Insert an empty line above the current line and indent it properly.
<kbd>S-RET</kbd> or <kbd>M-o</kbd> | Insert an empty line and indent it properly (as in most IDEs).
<kbd>C-S-up</kbd> or <kbd>M-S-up</kbd> | Move the current line or region up.
<kbd>C-S-down</kbd> or <kbd>M-S-down</kbd>| Move the current line or region down.
<kbd>C-c n</kbd> | Fix indentation in buffer and strip whitespace.
<kbd>C-c f</kbd> | Open recently visited file.
<kbd>C-M-\\</kbd> | Indent region (if selected) or the entire buffer.
<kbd>C-c u</kbd> | Open a new buffer containing the contents of URL.
<kbd>C-c e</kbd> | Eval a bit of Emacs Lisp code and replace it with its result.
<kbd>C-c s</kbd> | Swap two active windows.
<kbd>C-c D</kbd> | Delete current file and buffer.
<kbd>C-c d</kbd> | Duplicate the current line (or region).
<kbd>C-c M-d</kbd> | Duplicate and comment the current line (or region).
<kbd>C-c r</kbd> | Rename the current buffer and its visiting file if any.
<kbd>C-c t</kbd> | Open a terminal emulator (`ansi-term`).
<kbd>C-c k</kbd> | Kill all open buffers except the one you're currently in.
<kbd>C-c TAB</kbd> | Indent and copy region to clipboard
<kbd>C-c I</kbd> | Open user's init file.
<kbd>C-c S</kbd> | Open shell's init file.
<kbd>C-c . +</kbd> | Increment integer at point. Default is +1.
<kbd>C-c . -</kbd> | Decrement integer at point. Default is -1.
<kbd>C-c . *</kbd> | Multiply integer at point. Default is *2.
<kbd>C-c . /</kbd> | Divide integer at point. Default is /2.
<kbd>C-c . \\</kbd> | Modulo integer at point. Default is modulo 2.
<kbd>C-c . ^</kbd> | Power to the integer at point. Default is ^2.
<kbd>C-c . <</kbd> | Left-shift integer at point. Default is 1 position to the left.
<kbd>C-c . ></kbd> | Right-shift integer at point. Default is 1 position to the right.
<kbd>C-c . #</kbd> | Convert integer at point to specified base. Default is 10.
<kbd>C-c . %</kbd> | Replace integer at point with another specified integer.
<kbd>C-c . '</kbd> | Perform arithmetic operations on integer at point. User specifies the operator.
<kbd>Super-g</kbd> | Toggle between God mode and non-God mode
<kbd>Super-r</kbd> | Recent files
<kbd>Super-j</kbd> | Join lines
<kbd>Super-k</kbd> | Kill whole line
<kbd>Super-m m</kbd> | Magit status
<kbd>Super-m l</kbd> | Magit log
<kbd>Super-m f</kbd> | Magit file log
<kbd>Super-m b</kbd> | Magit blame mode
**Note**: For various arithmetic operations, the prefix `C-c .` only needs to be pressed once for the first operation.
For subsequent operations, only the appropriate operations (i.e. `+`, `-`, `*`, `/`... needs to be pressed).
#### macOS modifier keys
Prelude does not mess by default with the standard mapping of `Command` (to `Super`) and `Option` (to `Meta`).
If you want to swap them add this to your personal config:
```lisp
(setq mac-command-modifier 'meta)
(setq mac-option-modifier 'super)
```
You can also temporarily swap them with `C-c w` (`M-x prelude-swap-meta-and-super`).
**Note**: I'd highly recommend to all macOS users to consider
[remapping Return to
Control](http://emacsredux.com/blog/2013/11/12/a-crazy-productivity-boost-remap-return-to-control/)
instead. That's an epic productivity boost and it's not as crazy as it sounds!
#### Projectile
Here's a list of functionality provided by [Projectile](https://github.com/bbatsov/projectile):
Keybinding | Description
-------------------|------------------------------------------------------------
<kbd>C-c p f</kbd> | Display a list of all files in the project. With a prefix argument it will clear the cache first.
<kbd>C-c p d</kbd> | Display a list of all directories in the project. With a prefix argument it will clear the cache first.
<kbd>C-c p T</kbd> | Display a list of all test files(specs, features, etc) in the project.
<kbd>C-c p s g</kbd> | Run grep on the files in the project.
<kbd>C-c p s s</kbd> | Runs `ag` on the project. Requires the presence of `ag.el`.
<kbd>M-- C-c p s g</kbd> | Run grep on `projectile-grep-default-files` in the project.
<kbd>C-c p b</kbd> | Display a list of all project buffers currently open.
<kbd>C-c p o</kbd> | Runs `multi-occur` on all project buffers currently open.
<kbd>C-c p r</kbd> | Runs interactive query-replace on all files in the projects.
<kbd>C-c p i</kbd> | Invalidates the project cache (if existing).
<kbd>C-c p R</kbd> | Regenerates the projects `TAGS` file.
<kbd>C-c p k</kbd> | Kills all project buffers.
<kbd>C-c p D</kbd> | Opens the root of the project in `dired`.
<kbd>C-c p e</kbd> | Shows a list of recently visited project files.
<kbd>C-c p a</kbd> | Switch between files with the same name but different extensions.
<kbd>C-c p c</kbd> | Runs a standard compilation command for your type of project.
<kbd>C-c p P</kbd> | Runs a standard test command for your type of project.
<kbd>C-c p z</kbd> | Adds the currently visited to the cache.
<kbd>C-c p p</kbd> | Display a list of known projects you can switch to.
Prelude adds an extra keymap prefix `S-p` (`S` stands for
`Super`), so you can use `S-p` instead of `C-c p`. By default on Windows keyboard
`Super` is mapped to the `Windows` key and on macOS keyboards `Super` is mapped
to the `Command` key.
If you ever forget any of Projectile's keybindings just do a:
<kbd>C-c p C-h</kbd>
#### Helm
Helm is setup according to this guide: [A Package in a league of its own: Helm](http://tuhdo.github.io/helm-intro.html).
You can learn Helm usage and key bindings following the guide. <kbd>C-c h</kbd> is Prelude's default prefix key for Helm.
If you don't remember any key binding, append <kbd>C-h</kbd> after <kbd>C-c h</kbd> for a list of key bindings in Helm.
If you love Helm and want to use Helm globally with enhanced `helm-find-files`, `helm-buffer-lists`..., you will have to also add `(require 'prelude-helm-everywhere)`.
When `prelude-helm-everywhere` is activated, Helm enables these global key bindings:
Key binding | Description
-------------------|----------------------------------------------
<kbd>M-x</kbd> | Run [helm-M-x](http://tuhdo.github.io/helm-intro.html#sec-3), an interactive version of <kbd>M-x</kdb>.
<kbd>M-y</kbd> | Run [helm-show-kill-ring](http://tuhdo.github.io/helm-intro.html#sec-4), shows the content of `kill-ring`.
<kbd>C-x b </kbd> | Run [helm-mini](http://tuhdo.github.io/helm-intro.html#sec-5), an interactive version of `C-x b` with more features.
<kbd>C-x C-f</kbd> | Run [helm-find-files](http://tuhdo.github.io/helm-intro.html#sec-6), an interactive version of `find-file` with more features.
<kbd>C-h f </kbd> | Run [helm-apropos](http://tuhdo.github.io/helm-intro.html#sec-13), an interactive version of `apropos-command`.
<kbd>C-h r</kbd> | Run [helm-info-emacs](http://tuhdo.github.io/helm-intro.html#sec-14), an interactive version of `info-emacs-manual`.
<kbd>C-h C-l </kbd>| Run `helm-locate-library` that can search for locations of any file loaded into Emacs.
This key binding is activated in `shell-mode`:
Key Binding | Description
-------------------|----------------------------------------------
<kbd>C-c C-l</kbd> | Run `helm-comint-input-ring` that shows `shell` history using Helm interface.
This key bindings is activated in `eshell-mode`:
Key Binding | Description
-------------------|----------------------------------------------
<kbd>C-c C-l</kbd> | Run `helm-eshell-history` that shows `eshell` history using Helm interface.
If you prefer Ido in everywhere, you should not add `prelude-helm-everywhere`, so you can use Helm along with Ido and Prelude's default commands.
You can always reactivate Helm with `(prelude-global-helm-global-mode-on)`.
**NOTICE**: In `helm-M-x`, you have to pass prefix argument *AFTER* you run `helm-M-x`,
because your prefix argument will be displayed in the modeline when in `helm-M-x`
buffer. Passing prefix argument **BEFORE** =helm-M-x= **has no effect**.
#### Key-chords
**Key-chords are available only when the `prelude-key-chord` module has been enabled.**
Keybinding | Description
-------------------|----------------------------------------------
<kbd>jj</kbd> | Jump to the beginning of a word(`avy-goto-word-1`)
<kbd>jk</kbd> | Jump to a character(`avy-goto-char`)
<kbd>jl</kbd> | Jump to the beginning of a line(`avy-goto-line`)
<kbd>JJ</kbd> | Jump back to previous buffer(`crux-switch-to-previous-buffer`)
<kbd>uu</kbd> | View edits as a tree(`undo-tree-visualize`)
<kbd>xx</kbd> | Executed extended command(`execute-extended-command`)
<kbd>yy</kbd> | Browse the kill ring(`browse-kill-ring`)
##### Disabling key-chords
In some cases you may not want to have a key-chord that is defined by prelude,
in which case you can disable the binding in your `personal.el` file by setting
its command to `nil`. For example, to disable the `jj` key-chord add the
following line:
```lisp
(key-chord-define-global "jj" nil)
```
If you're an `evil-mode` user you'll probably do well to disable `key-chord-mode` altogether:
```lisp
(key-chord-mode -1)
```
#### vim emulation
If you want to use vim inside of emacs enable the `prelude-evil` module which provides
support for `evil-mode`.
## Automatic package installation
The default Prelude installation comes with a bare minimum of
functionality. It will however install add-ons for various programming
languages and frameworks on demand. For instance - if you try to open
a `.clj` file `clojure-mode`, `cider` and Prelude's enhanced Lisp
configuration will be installed automatically for you.
You can, of course, install anything you wish manually as well.
### Color Themes
Emacs provides a dozen of
built-in themes you can use out-of-the-box by invoking the `M-x
load-theme` command.
[Zenburn](https://github.com/bbatsov/zenburn-emacs) is the default
color theme in Prelude, but you can change it at your discretion. Why
Zenburn? I (and lots of hackers around the world) find it pretty neat
for some reason. Personally I find the default theme pretty tiresome
for the eyes, that's why I took that "controversial" decision to
replace it. You can, of course, easily go back to the default (or
select another theme entirely).
To disable Zenburn just put in your personal config the following
line:
```lisp
(disable-theme 'zenburn)
```
Or you can use another theme altogether by adding something in `personal/preload` like:
```lisp
(prelude-require-package 'solarized)
(setq prelude-theme 'solarized-dark)
```
**Note** [Solarized](https://github.com/bbatsov/zenburn-emacs) is not
available by default - you'll have to install it from MELPA first,
therefore the need for `prelude-require-package`. Alternatively you
can manually install the package like this - `M-x package-install RET
solarized-theme`.
Finally, if you don't want any theme at all, you can add this to your
`personal/preload`:
```lisp
(setq prelude-theme nil)
```
### Personalizing
**Fork** (instead of cloning) the official Prelude repo and add your
own touch to it. You're advised to **avoid changing stuff outside of
the personal folder** to avoid having to deal with git merge conflicts
in the future.
If you'd like to add some auto installation of packages in your
personal config use the following code:
```lisp
(prelude-require-packages '(some-package some-other-package))
```
If you require just a single package you can also use:
```lisp
(prelude-require-package 'some-package)
```
#### Preloading personal config
Sometimes you might want to load code before Prelude has started loading. Prelude will automatically preload all
Emacs Lisp files in your `personal/preload` directory. Note that at this point you can't using anything from
Prelude, except a few variables like `prelude-dir`, etc (since nothing is yet loaded).
#### Disabling whitespace-mode
Although `whitespace-mode` is awesome, some people might find it too
intrusive. You can disable it in your
personal config with the following bit of code:
```lisp
(setq prelude-whitespace nil)
```
If you like `whitespace-mode`, but prefer it to not automatically
cleanup your file on save, you can disable that behavior by setting
`prelude-clean-whitespace-on-save` to `nil` in your config file with:
```lisp
(setq prelude-clean-whitespace-on-save nil)
```
The `prelude-clean-whitespace-on-save` setting can also be set on a
per-file or directory basis by using a file variable or a
`.dir-locals.el` file.
#### Disable flyspell-mode
If you're not fond of spellchecking on the fly:
```lisp
(setq prelude-flyspell nil)
```
## Caveats & Pitfalls
### Updating bundled packages
Generally it's a good idea to do a package update before running
updating Prelude, since the latest Prelude code might depend on newer
versions of the bundled packages than you would currently have
installed.
If you're doing manual Prelude updates you should always do a package update first.
`M-x package-list-packages RET U x`
That's not necessary if you're using `M-x prelude-update`, since it
will automatically update the installed packages.
### Problems with flyspell-mode
Prelude makes heavy use of the flyspell-mode package for spell
checking of various things. The proper operation of flyspell depends
on the presence of the `aspell` program and an `en` dictionary on your
system. You can install `aspell` and the dictionary on OS X with
`homebrew` like this:
```bash
brew install aspell --with-lang=en
```
On Linux distros - just use your distro's package manager.
### Ugly colors in the terminal Emacs version
If your Emacs looks considerably uglier in a terminal (compared to the
GUI version) try adding this to your `.bashrc` or `.zshrc`:
```bash
export TERM=xterm-256color
```
Source the `.bashrc` file and start Emacs again.
### MELPA error on initial startup
If you get some http connection error related to the MELPA repo
just do a manual `M-x package-refresh-contents` and restart Emacs
afterwards.
### Warnings on arrow navigation in editor buffers
This is not a bug - it's a feature! I firmly believe that the one true
way to use Emacs is by using it the way it was intended to be used (as
far as navigation is concerned at least).
If you'd like to be take this a step further and disable the arrow key navigation
completely put this in your personal config:
```lisp
(setq guru-warn-only nil)
```
To disable `guru-mode` completely add the following snippet to your
personal Emacs config:
```lisp
(setq prelude-guru nil)
```
### Customized C-a behavior
Prelude overrides `C-a` to behave as described
[here](http://emacsredux.com/blog/2013/05/22/smarter-navigation-to-the-beginning-of-a-line/). If
you don't like that simply add this to your personal config:
```lisp
(global-set-key [remap move-beginning-of-line]
'move-beginning-of-line)
```
### Poor ido matching performance on large datasets
Prelude swaps the default `ido` flex matching with the more powerful
[ido-flx](https://github.com/lewang/flx).
The sorting algorithm `flx` uses is more complex, but yields better results.
On slower machines, it may be necessary to lower `flx-ido-threshold` to
ensure a smooth experience.
```lisp
(setq flx-ido-threshold 1000)
```
You can always disable the improved sorting algorithm all together like this:
```lisp
(flx-ido-mode -1)
```
### Windows compatibility
While everything in Prelude should work fine in Windows, I test it only
with Linux & OS X, so there are Windows related problems from time to
time. This situation will probably improve over time.
## Known issues
Check out the project's
[issue list](https://github.com/bbatsov/prelude/issues?sort=created&direction=desc&state=open)
a list of unresolved issues. By the way - feel free to fix any of them
and send me a pull request. :-)
## Support
Support is available via several channels:
* Prelude's Google Group <emacs-prelude@googlegroups.com>
* Prelude's Freenode channel (`#prelude-emacs`)
* [Gitter](https://gitter.im/bbatsov/prelude)
.
## Contributors
Here's a [list](https://github.com/bbatsov/prelude/contributors) of all the people who have contributed to the
development of Emacs Prelude.
## Bugs & Improvements
Bug reports and suggestions for improvements are always
welcome. GitHub pull requests are even better! :-)
Cheers,<br/>
[Bozhidar](https://twitter.com/bbatsov)
[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg

View File

@ -1 +0,0 @@
../.dotfiles/emacs/.emacs.d/core

View File

@ -0,0 +1,178 @@
;;; prelude-core.el --- Emacs Prelude: Core Prelude functions.
;;
;; Copyright © 2011-2017 Bozhidar Batsov
;;
;; Author: Bozhidar Batsov <bozhidar@batsov.com>
;; URL: https://github.com/bbatsov/prelude
;; Version: 1.0.0
;; Keywords: convenience
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Here are the definitions of most of the functions added by Prelude.
;;; 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
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
(require 'thingatpt)
(require 'dash)
(require 'ov)
(defun prelude-buffer-mode (buffer-or-name)
"Retrieve the `major-mode' of BUFFER-OR-NAME."
(with-current-buffer buffer-or-name
major-mode))
(defun prelude-search (query-url prompt)
"Open the search url constructed with the QUERY-URL.
PROMPT sets the `read-string prompt."
(browse-url
(concat query-url
(url-hexify-string
(if mark-active
(buffer-substring (region-beginning) (region-end))
(read-string prompt))))))
(defmacro prelude-install-search-engine (search-engine-name search-engine-url search-engine-prompt)
"Given some information regarding a search engine, install the interactive command to search through them"
`(defun ,(intern (format "prelude-%s" search-engine-name)) ()
,(format "Search %s with a query or region if any." search-engine-name)
(interactive)
(prelude-search ,search-engine-url ,search-engine-prompt)))
(prelude-install-search-engine "google" "http://www.google.com/search?q=" "Google: ")
(prelude-install-search-engine "youtube" "http://www.youtube.com/results?search_query=" "Search YouTube: ")
(prelude-install-search-engine "github" "https://github.com/search?q=" "Search GitHub: ")
(prelude-install-search-engine "duckduckgo" "https://duckduckgo.com/?t=lm&q=" "Search DuckDuckGo: ")
(defun prelude-todo-ov-evaporate (_ov _after _beg _end &optional _length)
(let ((inhibit-modification-hooks t))
(if _after (ov-reset _ov))))
(defun prelude-annotate-todo ()
"Put fringe marker on TODO: lines in the current buffer."
(interactive)
(ov-set (format "[[:space:]]*%s+[[:space:]]*TODO:" comment-start)
'before-string
(propertize (format "A")
'display '(left-fringe right-triangle))
'modification-hooks '(prelude-todo-ov-evaporate)))
(defun prelude-recompile-init ()
"Byte-compile all your dotfiles again."
(interactive)
(byte-recompile-directory prelude-dir 0))
(defvar prelude-tips
'("Press <C-c o> to open a file with external program."
"Press <C-c p f> to navigate a project's files with ido."
"Press <s-r> to open a recently visited file."
"Press <C-c p s g> to run grep on a project."
"Press <C-c p p> to switch between projects."
"Press <C-=> to expand the selected region."
"Press <C-c g> to search in Google."
"Press <C-c G> to search in GitHub."
"Press <C-c y> to search in YouTube."
"Press <C-c U> to search in DuckDuckGo."
"Press <C-c r> to rename the current buffer and the file it's visiting if any."
"Press <C-c t> to open a terminal in Emacs."
"Press <C-c k> to kill all the buffers, but the active one."
"Press <C-x g> to run magit-status."
"Press <C-c D> to delete the current file and buffer."
"Press <C-c s> to swap two windows."
"Press <S-RET> or <M-o> to open a line beneath the current one."
"Press <s-o> to open a line above the current one."
"Press <C-c C-z> in a Elisp buffer to launch an interactive Elisp shell."
"Press <C-Backspace> to kill a line backwards."
"Press <C-S-Backspace> or <s-k> to kill the whole line."
"Press <s-j> or <C-^> to join lines."
"Press <s-.> or <C-c j> to jump to the start of a word in any visible window."
"Press <f11> to toggle fullscreen mode."
"Press <f12> to toggle the menu bar."
"Explore the Tools->Prelude menu to find out about some of Prelude extensions to Emacs."
"Access the official Emacs manual by pressing <C-h r>."
"Visit the EmacsWiki at http://emacswiki.org to find out even more about Emacs."))
(defun prelude-tip-of-the-day ()
"Display a random entry from `prelude-tips'."
(interactive)
(when (and prelude-tips (not (window-minibuffer-p)))
;; pick a new random seed
(random t)
(message
(concat "Prelude tip: " (nth (random (length prelude-tips)) prelude-tips)))))
(defun prelude-eval-after-init (form)
"Add `(lambda () FORM)' to `after-init-hook'.
If Emacs has already finished initialization, also eval FORM immediately."
(let ((func (list 'lambda nil form)))
(add-hook 'after-init-hook func)
(when after-init-time
(eval form))))
(require 'epl)
(defun prelude-update ()
"Update Prelude to its latest version."
(interactive)
(when (y-or-n-p "Do you want to update Prelude? ")
(message "Updating installed packages...")
(epl-upgrade)
(message "Updating Prelude...")
(cd prelude-dir)
(shell-command "git pull")
(prelude-recompile-init)
(message "Update finished. Restart Emacs to complete the process.")))
(defun prelude-update-packages (&optional arg)
"Update Prelude's packages.
This includes package installed via `prelude-require-package'.
With a prefix ARG updates all installed packages."
(interactive "P")
(when (y-or-n-p "Do you want to update Prelude's packages? ")
(if arg
(epl-upgrade)
(epl-upgrade (-filter (lambda (p) (memq (epl-package-name p) prelude-packages))
(epl-installed-packages))))
(message "Update finished. Restart Emacs to complete the process.")))
;;; Emacs in OSX already has fullscreen support
;;; Emacs has a similar built-in command in 24.4
(defun prelude-fullscreen ()
"Make Emacs window fullscreen.
This follows freedesktop standards, should work in X servers."
(interactive)
(if (eq window-system 'x)
(x-send-client-message nil 0 nil "_NET_WM_STATE" 32
'(2 "_NET_WM_STATE_FULLSCREEN" 0))
(error "Only X server is supported")))
(defun prelude-wrap-with (s)
"Create a wrapper function for smartparens using S."
`(lambda (&optional arg)
(interactive "P")
(sp-wrap-with-pair ,s)))
(provide 'prelude-core)
;;; prelude-core.el ends here

View File

@ -0,0 +1,103 @@
;;; prelude-custom.el --- Emacs Prelude: Prelude's customizable variables.
;;
;; Copyright © 2011-2017 Bozhidar Batsov
;;
;; Author: Bozhidar Batsov <bozhidar@batsov.com>
;; URL: https://github.com/bbatsov/prelude
;; Version: 1.0.0
;; Keywords: convenience
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Refinements of the core editing experience in 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
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
;; customize
(defgroup prelude nil
"Emacs Prelude configuration."
:prefix "prelude-"
:group 'convenience)
(defcustom prelude-auto-save t
"Non-nil values enable Prelude's auto save."
:type 'boolean
:group 'prelude)
(defcustom prelude-guru t
"Non-nil values enable `guru-mode'."
:type 'boolean
:group 'prelude)
(defcustom prelude-whitespace t
"Non-nil values enable Prelude's whitespace visualization."
:type 'boolean
:group 'prelude)
(defcustom prelude-clean-whitespace-on-save t
"Cleanup whitespace from file before it's saved.
Will only occur if `prelude-whitespace' is also enabled."
:type 'boolean
:group 'prelude)
(defcustom prelude-flyspell t
"Non-nil values enable Prelude's flyspell support."
:type 'boolean
:group 'prelude)
(defcustom prelude-user-init-file (expand-file-name "personal/"
user-emacs-directory)
"Path to your personal customization file.
Prelude recommends you only put personal customizations in the
personal folder. This variable allows you to specify a specific
folder as the one that should be visited when running
`crux-find-user-init-file'. This can be easily set to the desired buffer
in lisp by putting `(setq prelude-user-init-file load-file-name)'
in the desired elisp file."
:type 'string
:group 'prelude)
(defcustom prelude-indent-sensitive-modes
'(conf-mode coffee-mode haml-mode python-mode slim-mode yaml-mode)
"Modes for which auto-indenting is suppressed."
:type 'list
:group 'prelude)
(defcustom prelude-yank-indent-modes '(LaTeX-mode TeX-mode)
"Modes in which to indent regions that are yanked (or yank-popped).
Only modes that don't derive from `prog-mode' should be listed here."
:type 'list
:group 'prelude)
(defcustom prelude-yank-indent-threshold 1000
"Threshold (# chars) over which indentation does not automatically occur."
:type 'number
:group 'prelude)
(defcustom prelude-theme 'zenburn
"The default color theme, change this in your /personal/preload config."
:type 'symbol
:group 'prelude)
(provide 'prelude-custom)
;;; prelude-custom.el ends here

View File

@ -0,0 +1,440 @@
;;; prelude-editor.el --- Emacs Prelude: enhanced core editing experience.
;;
;; Copyright © 2011-2017 Bozhidar Batsov
;;
;; Author: Bozhidar Batsov <bozhidar@batsov.com>
;; URL: https://github.com/bbatsov/prelude
;; Version: 1.0.0
;; Keywords: convenience
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Refinements of the core editing experience in 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
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
;; Death to the tabs! However, tabs historically indent to the next
;; 8-character offset; specifying anything else will cause *mass*
;; confusion, as it will change the appearance of every existing file.
;; In some cases (python), even worse -- it will change the semantics
;; (meaning) of the program.
;;
;; Emacs modes typically provide a standard means to change the
;; indentation width -- eg. c-basic-offset: use that to adjust your
;; personal indentation width, while maintaining the style (and
;; meaning) of any files you load.
(setq-default indent-tabs-mode nil) ;; don't use tabs to indent
(setq-default tab-width 8) ;; but maintain correct appearance
;; Newline at end of file
(setq require-final-newline t)
;; delete the selection with a keypress
(delete-selection-mode t)
;; store all backup and autosave files in the tmp dir
(setq backup-directory-alist
`((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms
`((".*" ,temporary-file-directory t)))
;; autosave the undo-tree history
(setq undo-tree-history-directory-alist
`((".*" . ,temporary-file-directory)))
(setq undo-tree-auto-save-history t)
;; revert buffers automatically when underlying files are changed externally
(global-auto-revert-mode t)
;; hippie expand is dabbrev expand on steroids
(setq hippie-expand-try-functions-list '(try-expand-dabbrev
try-expand-dabbrev-all-buffers
try-expand-dabbrev-from-kill
try-complete-file-name-partially
try-complete-file-name
try-expand-all-abbrevs
try-expand-list
try-expand-line
try-complete-lisp-symbol-partially
try-complete-lisp-symbol))
;; smart tab behavior - indent or complete
(setq tab-always-indent 'complete)
;; smart pairing for all
(require 'smartparens-config)
(setq sp-base-key-bindings 'paredit)
(setq sp-autoskip-closing-pair 'always)
(setq sp-hybrid-kill-entire-symbol nil)
(sp-use-paredit-bindings)
(show-smartparens-global-mode +1)
(define-key prog-mode-map (kbd "M-(") (prelude-wrap-with "("))
;; FIXME: pick terminal friendly binding
;; (define-key prog-mode-map (kbd "M-[") (prelude-wrap-with "["))
(define-key prog-mode-map (kbd "M-\"") (prelude-wrap-with "\""))
;; disable annoying blink-matching-paren
(setq blink-matching-paren nil)
;; diminish keeps the modeline tidy
(require 'diminish)
;; meaningful names for buffers with the same name
(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)
(setq uniquify-separator "/")
(setq uniquify-after-kill-buffer-p t) ; rename after killing uniquified
(setq uniquify-ignore-buffers-re "^\\*") ; don't muck with special buffers
;; saveplace remembers your location in a file when saving files
(setq save-place-file (expand-file-name "saveplace" prelude-savefile-dir))
;; activate it for all buffers
(if (< emacs-major-version 25)
(progn (require 'saveplace)
(setq-default save-place t))
(save-place-mode 1))
;; savehist keeps track of some history
(require 'savehist)
(setq savehist-additional-variables
;; search entries
'(search-ring regexp-search-ring)
;; save every minute
savehist-autosave-interval 60
;; keep the home clean
savehist-file (expand-file-name "savehist" prelude-savefile-dir))
(savehist-mode +1)
;; save recent files
(require 'recentf)
(setq recentf-save-file (expand-file-name "recentf" prelude-savefile-dir)
recentf-max-saved-items 500
recentf-max-menu-items 15
;; disable recentf-cleanup on Emacs start, because it can cause
;; problems with remote files
recentf-auto-cleanup 'never)
(defun prelude-recentf-exclude-p (file)
"A predicate to decide whether to exclude FILE from recentf."
(let ((file-dir (file-truename (file-name-directory file))))
(-any-p (lambda (dir)
(string-prefix-p dir file-dir))
(mapcar 'file-truename (list prelude-savefile-dir package-user-dir)))))
(add-to-list 'recentf-exclude 'prelude-recentf-exclude-p)
(recentf-mode +1)
;; use shift + arrow keys to switch between visible buffers
(require 'windmove)
(windmove-default-keybindings)
;; automatically save buffers associated with files on buffer switch
;; and on windows switch
(defun prelude-auto-save-command ()
"Save the current buffer if `prelude-auto-save' is not nil."
(when (and prelude-auto-save
buffer-file-name
(buffer-modified-p (current-buffer))
(file-writable-p buffer-file-name))
(save-buffer)))
(defmacro advise-commands (advice-name commands class &rest body)
"Apply advice named ADVICE-NAME to multiple COMMANDS.
The body of the advice is in BODY."
`(progn
,@(mapcar (lambda (command)
`(defadvice ,command (,class ,(intern (concat (symbol-name command) "-" advice-name)) activate)
,@body))
commands)))
;; advise all window switching functions
(advise-commands "auto-save"
(switch-to-buffer other-window windmove-up windmove-down windmove-left windmove-right)
before
(prelude-auto-save-command))
(add-hook 'mouse-leave-buffer-hook 'prelude-auto-save-command)
(when (version<= "24.4" emacs-version)
(add-hook 'focus-out-hook 'prelude-auto-save-command))
(defadvice set-buffer-major-mode (after set-major-mode activate compile)
"Set buffer major mode according to `auto-mode-alist'."
(let* ((name (buffer-name buffer))
(mode (assoc-default name auto-mode-alist 'string-match)))
(when (and mode (consp mode))
(setq mode (car mode)))
(with-current-buffer buffer (if mode (funcall mode)))))
;; highlight the current line
(global-hl-line-mode +1)
(require 'volatile-highlights)
(volatile-highlights-mode t)
(diminish 'volatile-highlights-mode)
;; note - this should be after volatile-highlights is required
;; add the ability to cut the current line, without marking it
(require 'rect)
(crux-with-region-or-line kill-region)
;; tramp, for sudo access
(require 'tramp)
;; keep in mind known issues with zsh - see emacs wiki
(setq tramp-default-method "ssh")
(set-default 'imenu-auto-rescan t)
;; flyspell-mode does spell-checking on the fly as you type
(require 'flyspell)
(setq ispell-program-name "aspell" ; use aspell instead of ispell
ispell-extra-args '("--sug-mode=ultra"))
(defun prelude-enable-flyspell ()
"Enable command `flyspell-mode' if `prelude-flyspell' is not nil."
(when (and prelude-flyspell (executable-find ispell-program-name))
(flyspell-mode +1)))
(defun prelude-cleanup-maybe ()
"Invoke `whitespace-cleanup' if `prelude-clean-whitespace-on-save' is not nil."
(when prelude-clean-whitespace-on-save
(whitespace-cleanup)))
(defun prelude-enable-whitespace ()
"Enable `whitespace-mode' if `prelude-whitespace' is not nil."
(when prelude-whitespace
;; keep the whitespace decent all the time (in this buffer)
(add-hook 'before-save-hook 'prelude-cleanup-maybe nil t)
(whitespace-mode +1)))
(add-hook 'text-mode-hook 'prelude-enable-flyspell)
(add-hook 'text-mode-hook 'prelude-enable-whitespace)
;; enable narrowing commands
(put 'narrow-to-region 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(put 'narrow-to-defun 'disabled nil)
;; enabled change region case commands
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
;; enable erase-buffer command
(put 'erase-buffer 'disabled nil)
(require 'expand-region)
;; bookmarks
(require 'bookmark)
(setq bookmark-default-file (expand-file-name "bookmarks" prelude-savefile-dir)
bookmark-save-flag 1)
;; projectile is a project management mode
(require 'projectile)
(setq projectile-cache-file (expand-file-name "projectile.cache" prelude-savefile-dir))
(projectile-global-mode t)
;; avy allows us to effectively navigate to visible things
(require 'avy)
(setq avy-background t)
(setq avy-style 'at-full)
;; anzu-mode enhances isearch & query-replace by showing total matches and current match position
(require 'anzu)
(diminish 'anzu-mode)
(global-anzu-mode)
(global-set-key (kbd "M-%") 'anzu-query-replace)
(global-set-key (kbd "C-M-%") 'anzu-query-replace-regexp)
;; dired - reuse current buffer by pressing 'a'
(put 'dired-find-alternate-file 'disabled nil)
;; always delete and copy recursively
(setq dired-recursive-deletes 'always)
(setq dired-recursive-copies 'always)
;; if there is a dired buffer displayed in the next window, use its
;; current subdir, instead of the current subdir of this dired buffer
(setq dired-dwim-target t)
;; enable some really cool extensions like C-x C-j(dired-jump)
(require 'dired-x)
;; ediff - don't start another frame
(require 'ediff)
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
;; clean up obsolete buffers automatically
(require 'midnight)
;; smarter kill-ring navigation
(require 'browse-kill-ring)
(browse-kill-ring-default-keybindings)
(global-set-key (kbd "s-y") 'browse-kill-ring)
(defadvice exchange-point-and-mark (before deactivate-mark activate compile)
"When called with no active region, do not activate mark."
(interactive
(list (not (region-active-p)))))
(require 'tabify)
(defmacro with-region-or-buffer (func)
"When called with no active region, call FUNC on current buffer."
`(defadvice ,func (before with-region-or-buffer activate compile)
(interactive
(if mark-active
(list (region-beginning) (region-end))
(list (point-min) (point-max))))))
(with-region-or-buffer indent-region)
(with-region-or-buffer untabify)
;; automatically indenting yanked text if in programming-modes
(defun yank-advised-indent-function (beg end)
"Do indentation, as long as the region isn't too large."
(if (<= (- end beg) prelude-yank-indent-threshold)
(indent-region beg end nil)))
(advise-commands "indent" (yank yank-pop) after
"If current mode is one of `prelude-yank-indent-modes',
indent yanked text (with prefix arg don't indent)."
(if (and (not (ad-get-arg 0))
(not (member major-mode prelude-indent-sensitive-modes))
(or (derived-mode-p 'prog-mode)
(member major-mode prelude-yank-indent-modes)))
(let ((transient-mark-mode nil))
(yank-advised-indent-function (region-beginning) (region-end)))))
;; abbrev config
(add-hook 'text-mode-hook 'abbrev-mode)
;; make a shell script executable automatically on save
(add-hook 'after-save-hook
'executable-make-buffer-file-executable-if-script-p)
;; .zsh file is shell script too
(add-to-list 'auto-mode-alist '("\\.zsh\\'" . shell-script-mode))
;; whitespace-mode config
(require 'whitespace)
(setq whitespace-line-column 80) ;; limit line length
(setq whitespace-style '(face tabs empty trailing lines-tail))
;; saner regex syntax
(require 're-builder)
(setq reb-re-syntax 'string)
(require 'eshell)
(setq eshell-directory-name (expand-file-name "eshell" prelude-savefile-dir))
(setq semanticdb-default-save-directory
(expand-file-name "semanticdb" prelude-savefile-dir))
;; Compilation from Emacs
(defun prelude-colorize-compilation-buffer ()
"Colorize a compilation mode buffer."
(interactive)
;; we don't want to mess with child modes such as grep-mode, ack, ag, etc
(when (eq major-mode 'compilation-mode)
(let ((inhibit-read-only t))
(ansi-color-apply-on-region (point-min) (point-max)))))
(require 'compile)
(setq compilation-ask-about-save nil ; Just save before compiling
compilation-always-kill t ; Just kill old compile processes before
; starting the new one
compilation-scroll-output 'first-error ; Automatically scroll to first
; error
)
;; Colorize output of Compilation Mode, see
;; http://stackoverflow.com/a/3072831/355252
(require 'ansi-color)
(add-hook 'compilation-filter-hook #'prelude-colorize-compilation-buffer)
;; enable Prelude's keybindings
(prelude-global-mode t)
;; sensible undo
(global-undo-tree-mode)
(diminish 'undo-tree-mode)
;; enable winner-mode to manage window configurations
(winner-mode +1)
;; diff-hl
(global-diff-hl-mode +1)
(add-hook 'dired-mode-hook 'diff-hl-dired-mode)
(add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh)
;; easy-kill
(global-set-key [remap kill-ring-save] 'easy-kill)
(global-set-key [remap mark-sexp] 'easy-mark)
;; operate-on-number
(require 'operate-on-number)
(require 'smartrep)
(smartrep-define-key global-map "C-c ."
'(("+" . apply-operation-to-number-at-point)
("-" . apply-operation-to-number-at-point)
("*" . apply-operation-to-number-at-point)
("/" . apply-operation-to-number-at-point)
("\\" . apply-operation-to-number-at-point)
("^" . apply-operation-to-number-at-point)
("<" . apply-operation-to-number-at-point)
(">" . apply-operation-to-number-at-point)
("#" . apply-operation-to-number-at-point)
("%" . apply-operation-to-number-at-point)
("'" . operate-on-number-at-point)))
(defadvice server-visit-files (before parse-numbers-in-lines (files proc &optional nowait) activate)
"Open file with emacsclient with cursors positioned on requested line.
Most of console-based utilities prints filename in format
'filename:linenumber'. So you may wish to open filename in that format.
Just call:
emacsclient filename:linenumber
and file 'filename' will be opened and cursor set on line 'linenumber'"
(ad-set-arg 0
(mapcar (lambda (fn)
(let ((name (car fn)))
(if (string-match "^\\(.*?\\):\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?$" name)
(cons
(match-string 1 name)
(cons (string-to-number (match-string 2 name))
(string-to-number (or (match-string 3 name) ""))))
fn))) files)))
;; use settings from .editorconfig file when present
(require 'editorconfig)
(editorconfig-mode 1)
(provide 'prelude-editor)
;;; prelude-editor.el ends here

View File

@ -0,0 +1,116 @@
;;; prelude-global-keybindings.el --- Emacs Prelude: some useful keybindings.
;;
;; Copyright © 2011-2017 Bozhidar Batsov
;;
;; Author: Bozhidar Batsov <bozhidar@batsov.com>
;; URL: https://github.com/bbatsov/prelude
;; Version: 1.0.0
;; Keywords: convenience
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Lots of useful keybindings.
;;; 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
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
;; Align your code in a pretty way.
(global-set-key (kbd "C-x \\") 'align-regexp)
;; Font size
(global-set-key (kbd "C-+") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)
;; Window switching. (C-x o goes to the next window)
(global-set-key (kbd "C-x O") (lambda ()
(interactive)
(other-window -1))) ;; back one
;; Indentation help
(global-set-key (kbd "C-^") 'crux-top-join-line)
;; Start proced in a similar manner to dired
(unless (eq system-type 'darwin)
(global-set-key (kbd "C-x p") 'proced))
;; Start eshell or switch to it if it's active.
(global-set-key (kbd "C-x m") 'eshell)
;; Start a new eshell even if one is active.
(global-set-key (kbd "C-x M") (lambda () (interactive) (eshell t)))
;; Start a regular shell if you prefer that.
(global-set-key (kbd "C-x M-m") 'shell)
;; If you want to be able to M-x without meta
(global-set-key (kbd "C-x C-m") 'smex)
;; A complementary binding to the apropos-command (C-h a)
(define-key 'help-command "A" 'apropos)
;; A quick major mode help with discover-my-major
(define-key 'help-command (kbd "C-m") 'discover-my-major)
(define-key 'help-command (kbd "C-f") 'find-function)
(define-key 'help-command (kbd "C-k") 'find-function-on-key)
(define-key 'help-command (kbd "C-v") 'find-variable)
(define-key 'help-command (kbd "C-l") 'find-library)
(define-key 'help-command (kbd "C-i") 'info-display-manual)
;; replace zap-to-char functionality with the more powerful zop-to-char
(global-set-key (kbd "M-z") 'zop-up-to-char)
(global-set-key (kbd "M-Z") 'zop-to-char)
;; kill lines backward
(global-set-key (kbd "C-<backspace>") (lambda ()
(interactive)
(kill-line 0)
(indent-according-to-mode)))
(global-set-key [remap kill-whole-line] 'crux-kill-whole-line)
;; Activate occur easily inside isearch
(define-key isearch-mode-map (kbd "C-o") 'isearch-occur)
;; use hippie-expand instead of dabbrev
(global-set-key (kbd "M-/") 'hippie-expand)
;; replace buffer-menu with ibuffer
(global-set-key (kbd "C-x C-b") 'ibuffer)
(unless (fboundp 'toggle-frame-fullscreen)
(global-set-key (kbd "<f11>") 'prelude-fullscreen))
;; toggle menu-bar visibility
(global-set-key (kbd "<f12>") 'menu-bar-mode)
(global-set-key (kbd "C-x g") 'magit-status)
(global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)
(global-set-key (kbd "C-=") 'er/expand-region)
(global-set-key (kbd "C-c j") 'avy-goto-word-or-subword-1)
(global-set-key (kbd "s-.") 'avy-goto-word-or-subword-1)
(global-set-key (kbd "s-w") 'ace-window)
(provide 'prelude-global-keybindings)
;;; prelude-global-keybindings.el ends here

View File

@ -0,0 +1,149 @@
;;; prelude-mode.el --- Emacs Prelude: minor mode
;;
;; Copyright © 2011-2017 Bozhidar Batsov
;;
;; Author: Bozhidar Batsov <bozhidar@batsov.com>
;; URL: https://github.com/bbatsov/prelude
;; Version: 1.0.0
;; Keywords: convenience
;; This file is not part of GNU Emacs.
;;; Commentary:
;; A minor mode defining a local keymap, plus a menu.
;;; 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
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
(require 'easymenu)
(require 'imenu-anywhere)
(require 'crux)
(defvar prelude-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c o") 'crux-open-with)
(define-key map (kbd "C-c g") 'prelude-google)
(define-key map (kbd "C-c G") 'prelude-github)
(define-key map (kbd "C-c y") 'prelude-youtube)
(define-key map (kbd "C-c U") 'prelude-duckduckgo)
;; mimic popular IDEs binding, note that it doesn't work in a terminal session
(define-key map (kbd "C-a") 'crux-move-beginning-of-line)
(define-key map [(shift return)] 'crux-smart-open-line)
(define-key map (kbd "M-o") 'crux-smart-open-line)
(define-key map [(control shift return)] 'crux-smart-open-line-above)
(define-key map [(control shift up)] 'move-text-up)
(define-key map [(control shift down)] 'move-text-down)
(define-key map [(meta shift up)] 'move-text-up)
(define-key map [(meta shift down)] 'move-text-down)
(define-key map (kbd "C-c n") 'crux-cleanup-buffer-or-region)
(define-key map (kbd "C-c f") 'crux-recentf-ido-find-file)
(define-key map (kbd "C-M-z") 'crux-indent-defun)
(define-key map (kbd "C-c u") 'crux-view-url)
(define-key map (kbd "C-c e") 'crux-eval-and-replace)
(define-key map (kbd "C-c s") 'crux-swap-windows)
(define-key map (kbd "C-c D") 'crux-delete-file-and-buffer)
(define-key map (kbd "C-c d") 'crux-duplicate-current-line-or-region)
(define-key map (kbd "C-c M-d") 'crux-duplicate-and-comment-current-line-or-region)
(define-key map (kbd "C-c r") 'crux-rename-buffer-and-file)
(define-key map (kbd "C-c t") 'crux-visit-term-buffer)
(define-key map (kbd "C-c k") 'crux-kill-other-buffers)
(define-key map (kbd "C-c TAB") 'crux-indent-rigidly-and-copy-to-clipboard)
(define-key map (kbd "C-c I") 'crux-find-user-init-file)
(define-key map (kbd "C-c S") 'crux-find-shell-init-file)
(define-key map (kbd "C-c i") 'imenu-anywhere)
;; extra prefix for projectile
(define-key map (kbd "s-p") 'projectile-command-map)
;; make some use of the Super key
(define-key map (kbd "s-g") 'god-local-mode)
(define-key map (kbd "s-r") 'crux-recentf-ido-find-file)
(define-key map (kbd "s-j") 'crux-top-join-line)
(define-key map (kbd "s-k") 'crux-kill-whole-line)
(define-key map (kbd "s-m m") 'magit-status)
(define-key map (kbd "s-m l") 'magit-log)
(define-key map (kbd "s-m f") 'magit-log-buffer-file)
(define-key map (kbd "s-m b") 'magit-blame)
(define-key map (kbd "s-o") 'crux-smart-open-line-above)
map)
"Keymap for Prelude mode.")
(defun prelude-mode-add-menu ()
"Add a menu entry for `prelude-mode' under Tools."
(easy-menu-add-item nil '("Tools")
'("Prelude"
("Files"
["Open with..." crux-open-with]
["Delete file and buffer" crux-delete-file-and-buffer]
["Rename buffer and file" crux-rename-buffer-and-file])
("Buffers"
["Clean up buffer or region" crux-cleanup-buffer-or-region]
["Kill other buffers" crux-kill-other-buffers])
("Editing"
["Insert empty line" prelude-insert-empty-line]
["Move line up" prelude-move-line-up]
["Move line down" prelude-move-line-down]
["Duplicate line or region" prelude-duplicate-current-line-or-region]
["Indent rigidly and copy to clipboard" crux-indent-rigidly-and-copy-to-clipboard]
["Insert date" crux-insert-date]
["Eval and replace" crux-eval-and-replace]
)
("Windows"
["Swap windows" crux-swap-windows])
("General"
["Visit term buffer" crux-visit-term-buffer]
["Search in Google" prelude-google]
["View URL" crux-view-url]))
"Search Files (Grep)...")
(easy-menu-add-item nil '("Tools") '("--") "Search Files (Grep)..."))
(defun prelude-mode-remove-menu ()
"Remove `prelude-mode' menu entry."
(easy-menu-remove-item nil '("Tools") "Prelude")
(easy-menu-remove-item nil '("Tools") "--"))
;; define minor mode
(define-minor-mode prelude-mode
"Minor mode to consolidate Emacs Prelude extensions.
\\{prelude-mode-map}"
:lighter " Pre"
:keymap prelude-mode-map
(if prelude-mode
;; on start
(prelude-mode-add-menu)
;; on stop
(prelude-mode-remove-menu)))
(define-globalized-minor-mode prelude-global-mode prelude-mode prelude-on)
(defun prelude-on ()
"Turn on `prelude-mode'."
(prelude-mode +1))
(defun prelude-off ()
"Turn off `prelude-mode'."
(prelude-mode -1))
(provide 'prelude-mode)
;;; prelude-mode.el ends here

View File

@ -0,0 +1,75 @@
;;; prelude-osx.el --- Emacs Prelude: OSX specific settings.
;;
;; Copyright © 2011-2017 Bozhidar Batsov
;;
;; Author: Bozhidar Batsov <bozhidar@batsov.com>
;; URL: https://github.com/bbatsov/prelude
;; Version: 1.0.0
;; Keywords: convenience
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Some OSX specific stuff.
;;; 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
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
;; On OS X Emacs doesn't use the shell PATH if it's not started from
;; the shell. Let's fix that:
(prelude-require-packages '(exec-path-from-shell vkill))
(require 'exec-path-from-shell)
(exec-path-from-shell-initialize)
;; It's all in the Meta
(setq ns-function-modifier 'hyper)
;; proced-mode doesn't work on OS X so we use vkill instead
(autoload 'vkill "vkill" nil t)
(global-set-key (kbd "C-x p") 'vkill)
(defun prelude-swap-meta-and-super ()
"Swap the mapping of Meta and Super.
Very useful for people using their Mac with a
Windows external keyboard from time to time."
(interactive)
(if (eq mac-command-modifier 'super)
(progn
(setq mac-command-modifier 'meta)
(setq mac-option-modifier 'super)
(message "Command is now bound to META and Option is bound to SUPER."))
(progn
(setq mac-command-modifier 'super)
(setq mac-option-modifier 'meta)
(message "Command is now bound to SUPER and Option is bound to META."))))
(define-key prelude-mode-map (kbd "C-c w") 'prelude-swap-meta-and-super)
(define-key prelude-mode-map (kbd "s-/") 'hippie-expand)
(menu-bar-mode +1)
;; Enable emoji, and stop the UI from freezing when trying to display them.
(if (fboundp 'set-fontset-font)
(set-fontset-font t 'unicode "Apple Color Emoji" nil 'prepend))
(provide 'prelude-osx)
;;; prelude-osx.el ends here

View File

@ -0,0 +1,217 @@
;;; prelude-packages.el --- Emacs Prelude: default package selection.
;;
;; Copyright © 2011-2017 Bozhidar Batsov
;;
;; Author: Bozhidar Batsov <bozhidar@batsov.com>
;; URL: https://github.com/bbatsov/prelude
;; Version: 1.0.0
;; Keywords: convenience
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Takes care of the automatic installation of all the packages required by
;; Emacs Prelude.
;;; 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
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
(require 'cl)
(require 'package)
;; accessing a package repo over https on Windows is a no go, so we
;; fallback to http there
(if (eq system-type 'windows-nt)
(add-to-list 'package-archives
'("melpa" . "http://melpa.org/packages/") t)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t))
;; load the pinned packages
(let ((prelude-pinned-packages-file (expand-file-name "prelude-pinned-packages.el" prelude-dir)))
(if (file-exists-p prelude-pinned-packages-file)
(load prelude-pinned-packages-file)))
;; set package-user-dir to be relative to Prelude install path
(setq package-user-dir (expand-file-name "elpa" prelude-dir))
(package-initialize)
(defvar prelude-packages
'(ace-window
avy
anzu
beacon
browse-kill-ring
crux
dash
discover-my-major
diff-hl
diminish
easy-kill
editorconfig
epl
expand-region
flycheck
gist
git-timemachine
gitconfig-mode
gitignore-mode
god-mode
grizzl
guru-mode
imenu-anywhere
ov
projectile
magit
move-text
operate-on-number
smart-mode-line
smartparens
smartrep
undo-tree
volatile-highlights
which-key
zenburn-theme
zop-to-char)
"A list of packages to ensure are installed at launch.")
(defun prelude-packages-installed-p ()
"Check if all packages in `prelude-packages' are installed."
(every #'package-installed-p prelude-packages))
(defun prelude-require-package (package)
"Install PACKAGE unless already installed."
(unless (memq package prelude-packages)
(add-to-list 'prelude-packages package))
(unless (package-installed-p package)
(package-install package)))
(defun prelude-require-packages (packages)
"Ensure PACKAGES are installed.
Missing packages are installed automatically."
(mapc #'prelude-require-package packages))
(define-obsolete-function-alias 'prelude-ensure-module-deps 'prelude-require-packages)
(defun prelude-install-packages ()
"Install all packages listed in `prelude-packages'."
(unless (prelude-packages-installed-p)
;; check for new packages (package versions)
(message "%s" "Emacs Prelude is now refreshing its package database...")
(package-refresh-contents)
(message "%s" " done.")
;; install the missing packages
(prelude-require-packages prelude-packages)))
;; run package installation
(prelude-install-packages)
(defun prelude-list-foreign-packages ()
"Browse third-party packages not bundled with Prelude.
Behaves similarly to `package-list-packages', but shows only the packages that
are installed and are not in `prelude-packages'. Useful for
removing unwanted packages."
(interactive)
(package-show-package-list
(set-difference package-activated-list prelude-packages)))
(defmacro prelude-auto-install (extension package mode)
"When file with EXTENSION is opened triggers auto-install of PACKAGE.
PACKAGE is installed only if not already present. The file is opened in MODE."
`(add-to-list 'auto-mode-alist
`(,extension . (lambda ()
(unless (package-installed-p ',package)
(package-install ',package))
(,mode)))))
(defvar prelude-auto-install-alist
'(("\\.clj\\'" clojure-mode clojure-mode)
("\\.cmake\\'" cmake-mode cmake-mode)
("CMakeLists\\.txt\\'" cmake-mode cmake-mode)
("\\.coffee\\'" coffee-mode coffee-mode)
("\\.css\\'" css-mode css-mode)
("\\.csv\\'" csv-mode csv-mode)
("Cask" cask-mode cask-mode)
("\\.d\\'" d-mode d-mode)
("\\.dart\\'" dart-mode dart-mode)
("\\.elm\\'" elm-mode elm-mode)
("\\.ex\\'" elixir-mode elixir-mode)
("\\.exs\\'" elixir-mode elixir-mode)
("\\.elixir\\'" elixir-mode elixir-mode)
("\\.erl\\'" erlang erlang-mode)
("\\.feature\\'" feature-mode feature-mode)
("\\.go\\'" go-mode go-mode)
("\\.groovy\\'" groovy-mode groovy-mode)
("\\.haml\\'" haml-mode haml-mode)
("\\.hs\\'" haskell-mode haskell-mode)
("\\.json\\'" json-mode json-mode)
("\\.kt\\'" kotlin-mode kotlin-mode)
("\\.kv\\'" kivy-mode kivy-mode)
("\\.latex\\'" auctex LaTeX-mode)
("\\.less\\'" less-css-mode less-css-mode)
("\\.lua\\'" lua-mode lua-mode)
("\\.markdown\\'" markdown-mode markdown-mode)
("\\.md\\'" markdown-mode markdown-mode)
("\\.ml\\'" tuareg tuareg-mode)
("\\.pp\\'" puppet-mode puppet-mode)
("\\.php\\'" php-mode php-mode)
("\\.proto\\'" protobuf-mode protobuf-mode)
("\\.pyd\\'" cython-mode cython-mode)
("\\.pyi\\'" cython-mode cython-mode)
("\\.pyx\\'" cython-mode cython-mode)
("PKGBUILD\\'" pkgbuild-mode pkgbuild-mode)
("\\.rs\\'" rust-mode rust-mode)
("\\.sass\\'" sass-mode sass-mode)
("\\.scala\\'" scala-mode scala-mode)
("\\.scss\\'" scss-mode scss-mode)
("\\.slim\\'" slim-mode slim-mode)
("\\.styl\\'" stylus-mode stylus-mode)
("\\.swift\\'" swift-mode swift-mode)
("\\.textile\\'" textile-mode textile-mode)
("\\.thrift\\'" thrift thrift-mode)
("\\.yml\\'" yaml-mode yaml-mode)
("\\.yaml\\'" yaml-mode yaml-mode)
("Dockerfile\\'" dockerfile-mode dockerfile-mode)))
;; markdown-mode doesn't have autoloads for the auto-mode-alist
;; so we add them manually if it's already installed
(when (package-installed-p 'markdown-mode)
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . gfm-mode))
(add-to-list 'auto-mode-alist '("\\.md\\'" . gfm-mode)))
(when (package-installed-p 'pkgbuild-mode)
(add-to-list 'auto-mode-alist '("PKGBUILD\\'" . pkgbuild-mode)))
;; build auto-install mappings
(mapc
(lambda (entry)
(let ((extension (car entry))
(package (cadr entry))
(mode (cadr (cdr entry))))
(unless (package-installed-p package)
(prelude-auto-install extension package mode))))
prelude-auto-install-alist)
(provide 'prelude-packages)
;; Local Variables:
;; byte-compile-warnings: (not cl-functions)
;; End:
;;; prelude-packages.el ends here

View File

@ -0,0 +1,92 @@
;;; prelude-ui.el --- Emacs Prelude: UI optimizations and tweaks.
;;
;; Copyright © 2011-2017 Bozhidar Batsov
;;
;; Author: Bozhidar Batsov <bozhidar@batsov.com>
;; URL: https://github.com/bbatsov/prelude
;; Version: 1.0.0
;; Keywords: convenience
;; This file is not part of GNU Emacs.
;;; Commentary:
;; We dispense with most of the point and click UI, reduce the startup noise,
;; configure smooth scolling and a nice theme that's easy on the eyes (zenburn).
;;; 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
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
;; the toolbar is just a waste of valuable screen estate
;; in a tty tool-bar-mode does not properly auto-load, and is
;; already disabled anyway
(when (fboundp 'tool-bar-mode)
(tool-bar-mode -1))
(menu-bar-mode -1)
;; the blinking cursor is nothing, but an annoyance
(blink-cursor-mode -1)
;; disable the annoying bell ring
(setq ring-bell-function 'ignore)
;; disable startup screen
(setq inhibit-startup-screen t)
;; nice scrolling
(setq scroll-margin 0
scroll-conservatively 100000
scroll-preserve-screen-position 1)
;; mode line settings
(line-number-mode t)
(column-number-mode t)
(size-indication-mode t)
;; enable y/n answers
(fset 'yes-or-no-p 'y-or-n-p)
;; more useful frame title, that show either a file or a
;; buffer name (if the buffer isn't visiting a file)
(setq frame-title-format
'("" invocation-name " Prelude - " (:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name))
"%b"))))
;; use zenburn as the default theme
(when prelude-theme
(load-theme prelude-theme t))
(require 'smart-mode-line)
(setq sml/no-confirm-load-theme t)
;; delegate theming to the currently active theme
(setq sml/theme nil)
(add-hook 'after-init-hook #'sml/setup)
;; show the cursor when moving after big movements in the window
(require 'beacon)
(beacon-mode +1)
;; show available keybindings after you start typing
(require 'which-key)
(which-key-mode +1)
(provide 'prelude-ui)
;;; prelude-ui.el ends here

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "ace-window" "ace-window.el" (23122 58391 938995
;;;;;; 97000))
;;;### (autoloads nil "ace-window" "ace-window.el" (23124 14342 502053
;;;;;; 963000))
;;; Generated autoloads from ace-window.el
(autoload 'ace-select-window "ace-window" "\

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "anzu" "anzu.el" (23122 58392 598998 364000))
;;;### (autoloads nil "anzu" "anzu.el" (23124 14342 908722 546000))
;;; Generated autoloads from anzu.el
(autoload 'anzu-mode "anzu" "\

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "async" "async.el" (23122 58415 119377 479000))
;;;### (autoloads nil "async" "async.el" (23124 14361 928812 182000))
;;; Generated autoloads from async.el
(autoload 'async-start-process "async" "\
@ -68,8 +68,8 @@ returns nil. It can still be useful, however, as an argument to
;;;***
;;;### (autoloads nil "async-bytecomp" "async-bytecomp.el" (23122
;;;;;; 58415 112707 813000))
;;;### (autoloads nil "async-bytecomp" "async-bytecomp.el" (23124
;;;;;; 14361 918812 135000))
;;; Generated autoloads from async-bytecomp.el
(autoload 'async-byte-recompile-directory "async-bytecomp" "\
@ -97,8 +97,8 @@ Async compilation of packages can be controlled by
;;;***
;;;### (autoloads nil "dired-async" "dired-async.el" (23122 58415
;;;;;; 99368 482000))
;;;### (autoloads nil "dired-async" "dired-async.el" (23124 14361
;;;;;; 902145 390000))
;;; Generated autoloads from dired-async.el
(defvar dired-async-mode nil "\
@ -138,8 +138,8 @@ Run dired-do-rename asynchronously.
;;;***
;;;### (autoloads nil nil ("async-pkg.el" "smtpmail-async.el") (23122
;;;;;; 58415 129381 977000))
;;;### (autoloads nil nil ("async-pkg.el" "smtpmail-async.el") (23124
;;;;;; 14361 938812 229000))
;;;***

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "avy" "avy.el" (23122 58391 458992 721000))
;;;### (autoloads nil "avy" "avy.el" (23124 14342 48718 493000))
;;; Generated autoloads from avy.el
(autoload 'avy-goto-char "avy" "\

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "beacon" "beacon.el" (23122 58394 302340 129000))
;;;### (autoloads nil "beacon" "beacon.el" (23124 14344 338729 285000))
;;; Generated autoloads from beacon.el
(autoload 'beacon-blink "beacon" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "browse-kill-ring" "browse-kill-ring.el" (23122
;;;;;; 58394 995676 895000))
;;;### (autoloads nil "browse-kill-ring" "browse-kill-ring.el" (23124
;;;;;; 14344 845398 339000))
;;; Generated autoloads from browse-kill-ring.el
(autoload 'browse-kill-ring-default-keybindings "browse-kill-ring" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "company" "company.el" (23122 58435 129482
;;;;;; 747000))
;;;### (autoloads nil "company" "company.el" (23124 14379 415562
;;;;;; 107000))
;;; Generated autoloads from company.el
(autoload 'company-mode "company" "\
@ -74,8 +74,8 @@ inserted.
;;;***
;;;### (autoloads nil "company-abbrev" "company-abbrev.el" (23122
;;;;;; 58435 256179 919000))
;;;### (autoloads nil "company-abbrev" "company-abbrev.el" (23124
;;;;;; 14379 555562 780000))
;;; Generated autoloads from company-abbrev.el
(autoload 'company-abbrev "company-abbrev" "\
@ -85,8 +85,8 @@ inserted.
;;;***
;;;### (autoloads nil "company-bbdb" "company-bbdb.el" (23122 58435
;;;;;; 216170 286000))
;;;### (autoloads nil "company-bbdb" "company-bbdb.el" (23124 14379
;;;;;; 508895 889000))
;;; Generated autoloads from company-bbdb.el
(autoload 'company-bbdb "company-bbdb" "\
@ -96,8 +96,8 @@ inserted.
;;;***
;;;### (autoloads nil "company-css" "company-css.el" (23122 58435
;;;;;; 119480 339000))
;;;### (autoloads nil "company-css" "company-css.el" (23124 14379
;;;;;; 405562 59000))
;;; Generated autoloads from company-css.el
(autoload 'company-css "company-css" "\
@ -107,8 +107,8 @@ inserted.
;;;***
;;;### (autoloads nil "company-dabbrev" "company-dabbrev.el" (23122
;;;;;; 58435 172826 517000))
;;;### (autoloads nil "company-dabbrev" "company-dabbrev.el" (23124
;;;;;; 14379 462228 998000))
;;; Generated autoloads from company-dabbrev.el
(autoload 'company-dabbrev "company-dabbrev" "\
@ -119,7 +119,7 @@ dabbrev-like `company-mode' completion backend.
;;;***
;;;### (autoloads nil "company-dabbrev-code" "company-dabbrev-code.el"
;;;;;; (23122 58435 156155 836000))
;;;;;; (23124 14379 445562 251000))
;;; Generated autoloads from company-dabbrev-code.el
(autoload 'company-dabbrev-code "company-dabbrev-code" "\
@ -131,8 +131,8 @@ comments or strings.
;;;***
;;;### (autoloads nil "company-elisp" "company-elisp.el" (23122 58435
;;;;;; 272850 600000))
;;;### (autoloads nil "company-elisp" "company-elisp.el" (23124 14379
;;;;;; 572229 527000))
;;; Generated autoloads from company-elisp.el
(autoload 'company-elisp "company-elisp" "\
@ -142,8 +142,8 @@ comments or strings.
;;;***
;;;### (autoloads nil "company-etags" "company-etags.el" (23122 58435
;;;;;; 139485 155000))
;;;### (autoloads nil "company-etags" "company-etags.el" (23124 14379
;;;;;; 425562 155000))
;;; Generated autoloads from company-etags.el
(autoload 'company-etags "company-etags" "\
@ -153,8 +153,8 @@ comments or strings.
;;;***
;;;### (autoloads nil "company-files" "company-files.el" (23122 58435
;;;;;; 179494 789000))
;;;### (autoloads nil "company-files" "company-files.el" (23124 14379
;;;;;; 472229 46000))
;;; Generated autoloads from company-files.el
(autoload 'company-files "company-files" "\
@ -166,8 +166,8 @@ File paths with spaces are only supported inside strings.
;;;***
;;;### (autoloads nil "company-gtags" "company-gtags.el" (23122 58435
;;;;;; 76136 569000))
;;;### (autoloads nil "company-gtags" "company-gtags.el" (23124 14379
;;;;;; 362228 518000))
;;; Generated autoloads from company-gtags.el
(autoload 'company-gtags "company-gtags" "\
@ -177,8 +177,8 @@ File paths with spaces are only supported inside strings.
;;;***
;;;### (autoloads nil "company-ispell" "company-ispell.el" (23122
;;;;;; 58435 266182 328000))
;;;### (autoloads nil "company-ispell" "company-ispell.el" (23124
;;;;;; 14379 562229 478000))
;;; Generated autoloads from company-ispell.el
(autoload 'company-ispell "company-ispell" "\
@ -188,8 +188,8 @@ File paths with spaces are only supported inside strings.
;;;***
;;;### (autoloads nil "company-keywords" "company-keywords.el" (23122
;;;;;; 58435 199499 605000))
;;;### (autoloads nil "company-keywords" "company-keywords.el" (23124
;;;;;; 14379 488895 793000))
;;; Generated autoloads from company-keywords.el
(autoload 'company-keywords "company-keywords" "\
@ -199,8 +199,8 @@ File paths with spaces are only supported inside strings.
;;;***
;;;### (autoloads nil "company-nxml" "company-nxml.el" (23122 58435
;;;;;; 232840 967000))
;;;### (autoloads nil "company-nxml" "company-nxml.el" (23124 14379
;;;;;; 525562 636000))
;;; Generated autoloads from company-nxml.el
(autoload 'company-nxml "company-nxml" "\
@ -210,8 +210,8 @@ File paths with spaces are only supported inside strings.
;;;***
;;;### (autoloads nil "company-oddmuse" "company-oddmuse.el" (23122
;;;;;; 58435 102809 658000))
;;;### (autoloads nil "company-oddmuse" "company-oddmuse.el" (23124
;;;;;; 14379 388895 313000))
;;; Generated autoloads from company-oddmuse.el
(autoload 'company-oddmuse "company-oddmuse" "\
@ -221,8 +221,8 @@ File paths with spaces are only supported inside strings.
;;;***
;;;### (autoloads nil "company-semantic" "company-semantic.el" (23122
;;;;;; 58435 86138 978000))
;;;### (autoloads nil "company-semantic" "company-semantic.el" (23124
;;;;;; 14379 368895 217000))
;;; Generated autoloads from company-semantic.el
(autoload 'company-semantic "company-semantic" "\
@ -232,8 +232,8 @@ File paths with spaces are only supported inside strings.
;;;***
;;;### (autoloads nil "company-tempo" "company-tempo.el" (23122 58435
;;;;;; 162824 108000))
;;;### (autoloads nil "company-tempo" "company-tempo.el" (23124 14379
;;;;;; 452228 950000))
;;; Generated autoloads from company-tempo.el
(autoload 'company-tempo "company-tempo" "\
@ -243,8 +243,8 @@ File paths with spaces are only supported inside strings.
;;;***
;;;### (autoloads nil "company-tng" "company-tng.el" (23122 58435
;;;;;; 222838 558000))
;;;### (autoloads nil "company-tng" "company-tng.el" (23124 14379
;;;;;; 515562 588000))
;;; Generated autoloads from company-tng.el
(autoload 'company-tng-frontend "company-tng" "\
@ -262,8 +262,8 @@ Applies the default configuration to enable company-tng.
;;;***
;;;### (autoloads nil "company-xcode" "company-xcode.el" (23122 58435
;;;;;; 249511 647000))
;;;### (autoloads nil "company-xcode" "company-xcode.el" (23124 14379
;;;;;; 545562 732000))
;;; Generated autoloads from company-xcode.el
(autoload 'company-xcode "company-xcode" "\
@ -274,7 +274,7 @@ Applies the default configuration to enable company-tng.
;;;***
;;;### (autoloads nil "company-yasnippet" "company-yasnippet.el"
;;;;;; (23122 58435 239509 239000))
;;;;;; (23124 14379 535562 684000))
;;; Generated autoloads from company-yasnippet.el
(autoload 'company-yasnippet "company-yasnippet" "\
@ -306,7 +306,7 @@ shadow backends that come after it. Recommended usages:
;;;### (autoloads nil nil ("company-capf.el" "company-clang.el" "company-cmake.el"
;;;;;; "company-eclim.el" "company-pkg.el" "company-template.el")
;;;;;; (23122 58435 206167 878000))
;;;;;; (23124 14379 498895 841000))
;;;***

View File

@ -1,402 +0,0 @@
;;; counsel-autoloads.el --- automatically extracted autoloads
;;
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "counsel" "counsel.el" (23122 58433 455730
;;;;;; 122000))
;;; Generated autoloads from counsel.el
(autoload 'counsel-el "counsel" "\
Elisp completion at point.
\(fn)" t nil)
(autoload 'counsel-cl "counsel" "\
Common Lisp completion at point.
\(fn)" t nil)
(autoload 'counsel-clj "counsel" "\
Clojure completion at point.
\(fn)" t nil)
(autoload 'counsel-unicode-char "counsel" "\
Insert COUNT copies of a Unicode character at point.
COUNT defaults to 1.
\(fn &optional COUNT)" t nil)
(autoload 'counsel-describe-variable "counsel" "\
Forward to `describe-variable'.
Variables declared using `defcustom' are highlighted according to
`ivy-highlight-face'.
\(fn)" t nil)
(autoload 'counsel-describe-function "counsel" "\
Forward to `describe-function'.
Interactive functions (i.e., commands) are highlighted according
to `ivy-highlight-face'.
\(fn)" t nil)
(autoload 'counsel-set-variable "counsel" "\
Set a variable, with completion.
When the selected variable is a `defcustom' with the type boolean
or radio, offer completion of all possible values.
Otherwise, offer a variant of `eval-expression', with the initial
input corresponding to the chosen variable.
\(fn)" t nil)
(autoload 'counsel-info-lookup-symbol "counsel" "\
Forward to `info-lookup-symbol' with ivy completion.
\(fn SYMBOL &optional MODE)" t nil)
(autoload 'counsel-file-register "counsel" "\
Search file in register.
You cannot use Emacs' normal register commands to create file
registers. Instead you must use the `set-register' function like
so: `(set-register ?i \"/home/eric/.emacs.d/init.el\")'. Now you
can use `C-x r j i' to open that file.
\(fn)" t nil)
(autoload 'counsel-bookmark "counsel" "\
Forward to `bookmark-jump' or `bookmark-set' if bookmark doesn't exist.
\(fn)" t nil)
(autoload 'counsel-M-x "counsel" "\
Ivy version of `execute-extended-command'.
Optional INITIAL-INPUT is the initial input in the minibuffer.
\(fn &optional INITIAL-INPUT)" t nil)
(autoload 'counsel-load-library "counsel" "\
Load a selected the Emacs Lisp library.
The libraries are offered from `load-path'.
\(fn)" t nil)
(autoload 'counsel-find-library "counsel" "\
Visit a selected the Emacs Lisp library.
The libraries are offered from `load-path'.
\(fn)" t nil)
(autoload 'counsel-load-theme "counsel" "\
Forward to `load-theme'.
Usable with `ivy-resume', `ivy-next-line-and-call' and
`ivy-previous-line-and-call'.
\(fn)" t nil)
(autoload 'counsel-descbinds "counsel" "\
Show a list of all defined keys and their definitions.
If non-nil, show only bindings that start with PREFIX.
BUFFER defaults to the current one.
\(fn &optional PREFIX BUFFER)" t nil)
(autoload 'counsel-git "counsel" "\
Find file in the current Git repository.
INITIAL-INPUT can be given as the initial minibuffer input.
\(fn &optional INITIAL-INPUT)" t nil)
(autoload 'counsel-git-grep "counsel" "\
Grep for a string in the current git repository.
When CMD is a string, use it as a \"git grep\" command.
When CMD is non-nil, prompt for a specific \"git grep\" command.
INITIAL-INPUT can be given as the initial minibuffer input.
\(fn &optional CMD INITIAL-INPUT)" t nil)
(autoload 'counsel-git-stash "counsel" "\
Search through all available git stashes.
\(fn)" t nil)
(autoload 'counsel-git-change-worktree "counsel" "\
Find the file corresponding to the current buffer on a different worktree.
\(fn)" t nil)
(autoload 'counsel-git-checkout "counsel" "\
Call the \"git checkout\" command.
\(fn)" t nil)
(autoload 'counsel-git-log "counsel" "\
Call the \"git log --grep\" shell command.
\(fn)" t nil)
(autoload 'counsel-find-file "counsel" "\
Forward to `find-file'.
When INITIAL-INPUT is non-nil, use it in the minibuffer during completion.
\(fn &optional INITIAL-INPUT)" t nil)
(autoload 'counsel-recentf "counsel" "\
Find a file on `recentf-list'.
\(fn)" t nil)
(autoload 'counsel-locate "counsel" "\
Call the \"locate\" shell command.
INITIAL-INPUT can be given as the initial minibuffer input.
\(fn &optional INITIAL-INPUT)" t nil)
(autoload 'counsel-fzf "counsel" "\
Open a file using the fzf shell command.
INITIAL-INPUT can be given as the initial minibuffer input.
INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
FZF-PROMPT, if non-nil, is passed as `ivy-read' prompt argument.
\(fn &optional INITIAL-INPUT INITIAL-DIRECTORY FZF-PROMPT)" t nil)
(autoload 'counsel-dpkg "counsel" "\
Call the \"dpkg\" shell command.
\(fn)" t nil)
(autoload 'counsel-rpm "counsel" "\
Call the \"rpm\" shell command.
\(fn)" t nil)
(autoload 'counsel-file-jump "counsel" "\
Jump to a file below the current directory.
List all files within the current directory or any of its subdirectories.
INITIAL-INPUT can be given as the initial minibuffer input.
INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
\(fn &optional INITIAL-INPUT INITIAL-DIRECTORY)" t nil)
(autoload 'counsel-dired-jump "counsel" "\
Jump to a directory (in dired) below the current directory.
List all subdirectories within the current directory.
INITIAL-INPUT can be given as the initial minibuffer input.
INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
\(fn &optional INITIAL-INPUT INITIAL-DIRECTORY)" t nil)
(autoload 'counsel-ag "counsel" "\
Grep for a string in the current directory using ag.
INITIAL-INPUT can be given as the initial minibuffer input.
INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
EXTRA-AG-ARGS string, if non-nil, is appended to `counsel-ag-base-command'.
AG-PROMPT, if non-nil, is passed as `ivy-read' prompt argument.
\(fn &optional INITIAL-INPUT INITIAL-DIRECTORY EXTRA-AG-ARGS AG-PROMPT)" t nil)
(autoload 'counsel-pt "counsel" "\
Grep for a string in the current directory using pt.
INITIAL-INPUT can be given as the initial minibuffer input.
This uses `counsel-ag' with `counsel-pt-base-command' instead of
`counsel-ag-base-command'.
\(fn &optional INITIAL-INPUT)" t nil)
(autoload 'counsel-ack "counsel" "\
Grep for a string in the current directory using ack.
INITIAL-INPUT can be given as the initial minibuffer input.
This uses `counsel-ag' with `counsel-ack-base-command' replacing
`counsel-ag-base-command'.
\(fn &optional INITIAL-INPUT)" t nil)
(autoload 'counsel-rg "counsel" "\
Grep for a string in the current directory using rg.
INITIAL-INPUT can be given as the initial minibuffer input.
INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
EXTRA-RG-ARGS string, if non-nil, is appended to `counsel-rg-base-command'.
RG-PROMPT, if non-nil, is passed as `ivy-read' prompt argument.
\(fn &optional INITIAL-INPUT INITIAL-DIRECTORY EXTRA-RG-ARGS RG-PROMPT)" t nil)
(autoload 'counsel-grep "counsel" "\
Grep for a string in the file visited by the current buffer.
When non-nil, INITIAL-INPUT is the initial search pattern.
\(fn &optional INITIAL-INPUT)" t nil)
(autoload 'counsel-grep-or-swiper "counsel" "\
Call `swiper' for small buffers and `counsel-grep' for large ones.
When non-nil, INITIAL-INPUT is the initial search pattern.
\(fn &optional INITIAL-INPUT)" t nil)
(autoload 'counsel-org-tag "counsel" "\
Add or remove tags in `org-mode'.
\(fn)" t nil)
(autoload 'counsel-org-tag-agenda "counsel" "\
Set tags for the current agenda item.
\(fn)" t nil)
(autoload 'counsel-org-goto "counsel" "\
Go to a different location in the current file.
\(fn)" t nil)
(autoload 'counsel-org-goto-all "counsel" "\
Go to a different location in any org file.
\(fn)" t nil)
(autoload 'counsel-org-file "counsel" "\
Browse all attachments for current Org file.
\(fn)" t nil)
(autoload 'counsel-org-capture "counsel" "\
Capture something.
\(fn)" t nil)
(autoload 'counsel-tmm "counsel" "\
Text-mode emulation of looking and choosing from a menubar.
\(fn)" t nil)
(autoload 'counsel-yank-pop "counsel" "\
Ivy replacement for `yank-pop'.
ARG has the same meaning as in `yank-pop', but its default value
can be controlled with `counsel-yank-pop-preselect-last', which
see. See also `counsel-yank-pop-filter' for how to filter
candidates.
Note: Duplicate elements of `kill-ring' are always deleted.
\(fn &optional ARG)" t nil)
(autoload 'counsel-imenu "counsel" "\
Jump to a buffer position indexed by imenu.
\(fn)" t nil)
(autoload 'counsel-list-processes "counsel" "\
Offer completion for `process-list'.
The default action deletes the selected process.
An extra action allows to switch to the process buffer.
\(fn)" t nil)
(autoload 'counsel-expression-history "counsel" "\
Select an element of `read-expression-history'.
And insert it into the minibuffer. Useful during `eval-expression'.
\(fn)" t nil)
(autoload 'counsel-shell-command-history "counsel" "\
Browse shell command history.
\(fn)" t nil)
(autoload 'counsel-minibuffer-history "counsel" "\
Browse minibuffer history.
\(fn)" t nil)
(autoload 'counsel-esh-history "counsel" "\
Browse Eshell history.
\(fn)" t nil)
(autoload 'counsel-shell-history "counsel" "\
Browse shell history.
\(fn)" t nil)
(autoload 'counsel-rhythmbox "counsel" "\
Choose a song from the Rhythmbox library to play or enqueue.
\(fn)" t nil)
(autoload 'counsel-linux-app "counsel" "\
Launch a Linux desktop application, similar to Alt-<F2>.
\(fn)" t nil)
(autoload 'counsel-company "counsel" "\
Complete using `company-candidates'.
\(fn)" t nil)
(autoload 'counsel-colors-emacs "counsel" "\
Show a list of all supported colors for a particular frame.
You can insert or kill the name or the hexadecimal rgb value of the
selected candidate.
\(fn)" t nil)
(autoload 'counsel-colors-web "counsel" "\
Show a list of all W3C web colors for use in CSS.
You can insert or kill the name or the hexadecimal rgb value of the
selected candidate.
\(fn)" t nil)
(autoload 'counsel-org-agenda-headlines "counsel" "\
Choose from headers of `org-mode' files in the agenda.
\(fn)" t nil)
(autoload 'counsel-irony "counsel" "\
Inline C/C++ completion using Irony.
\(fn)" t nil)
(autoload 'counsel-apropos "counsel" "\
Show all matching symbols.
See `apropos' for further information about what is considered
a symbol and how to search for them.
\(fn)" t nil)
(autoload 'counsel-switch-to-shell-buffer "counsel" "\
Switch to a shell buffer, or create one.
\(fn)" t nil)
(defvar counsel-mode nil "\
Non-nil if Counsel mode is enabled.
See the `counsel-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `counsel-mode'.")
(custom-autoload 'counsel-mode "counsel" nil)
(autoload 'counsel-mode "counsel" "\
Toggle Counsel mode on or off.
Turn Counsel mode on if ARG is positive, off otherwise. Counsel
mode remaps built-in emacs functions that have counsel
replacements.
\(fn &optional ARG)" t nil)
;;;***
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; End:
;;; counsel-autoloads.el ends here

View File

@ -1,2 +0,0 @@
;;; -*- no-byte-compile: t -*-
(define-package "counsel" "20180106.127" "Various completion functions using Ivy" '((emacs "24.3") (swiper "0.9.0")) :commit "e5c5037fd5f2735b11fc90363f312431619fa8c2" :url "https://github.com/abo-abo/swiper" :keywords '("completion" "matching"))

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "crux" "crux.el" (23122 58395 442345 773000))
;;;### (autoloads nil "crux" "crux.el" (23124 14345 312067 205000))
;;; Generated autoloads from crux.el
(defvar crux-reopen-as-root-mode nil "\

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil nil ("dash.el") (23122 58396 335683 527000))
;;;### (autoloads nil nil ("dash.el") (23124 14346 52070 693000))
;;;***

View File

@ -3,7 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "diff-hl" "diff-hl.el" (23122 58398 15691 845000))
;;;### (autoloads nil "diff-hl" "diff-hl.el" (23124 14347 452077
;;;;;; 291000))
;;; Generated autoloads from diff-hl.el
(autoload 'diff-hl-mode "diff-hl" "\
@ -40,8 +41,8 @@ See `diff-hl-mode' for more information on Diff-Hl mode.
;;;***
;;;### (autoloads nil "diff-hl-amend" "diff-hl-amend.el" (23122 58398
;;;;;; 25691 894000))
;;;### (autoloads nil "diff-hl-amend" "diff-hl-amend.el" (23124 14347
;;;;;; 462077 338000))
;;; Generated autoloads from diff-hl-amend.el
(autoload 'diff-hl-amend-mode "diff-hl-amend" "\
@ -76,8 +77,8 @@ See `diff-hl-amend-mode' for more information on Diff-Hl-Amend mode.
;;;***
;;;### (autoloads nil "diff-hl-dired" "diff-hl-dired.el" (23122 58398
;;;;;; 42358 643000))
;;;### (autoloads nil "diff-hl-dired" "diff-hl-dired.el" (23124 14347
;;;;;; 478744 83000))
;;; Generated autoloads from diff-hl-dired.el
(autoload 'diff-hl-dired-mode "diff-hl-dired" "\
@ -92,8 +93,8 @@ Toggle VC diff highlighting on the side of a Dired window.
;;;***
;;;### (autoloads nil "diff-hl-flydiff" "diff-hl-flydiff.el" (23122
;;;;;; 58398 9025 145000))
;;;### (autoloads nil "diff-hl-flydiff" "diff-hl-flydiff.el" (23124
;;;;;; 14347 445410 593000))
;;; Generated autoloads from diff-hl-flydiff.el
(defvar diff-hl-flydiff-mode nil "\
@ -114,8 +115,8 @@ This is a global minor mode. It alters how `diff-hl-mode' works.
;;;***
;;;### (autoloads nil "diff-hl-margin" "diff-hl-margin.el" (23122
;;;;;; 58397 999025 96000))
;;;### (autoloads nil "diff-hl-margin" "diff-hl-margin.el" (23124
;;;;;; 14347 435410 545000))
;;; Generated autoloads from diff-hl-margin.el
(defvar diff-hl-margin-mode nil "\
@ -135,7 +136,8 @@ Toggle displaying `diff-hl-mode' highlights on the margin.
;;;***
;;;### (autoloads nil nil ("diff-hl-pkg.el") (23122 58398 35691 944000))
;;;### (autoloads nil nil ("diff-hl-pkg.el") (23124 14347 472077
;;;;;; 385000))
;;;***

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "diminish" "diminish.el" (23122 58398 635694
;;;;;; 914000))
;;;### (autoloads nil "diminish" "diminish.el" (23124 14347 982079
;;;;;; 788000))
;;; Generated autoloads from diminish.el
(autoload 'diminish "diminish" "\

View File

@ -4,7 +4,7 @@
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "discover-my-major" "discover-my-major.el"
;;;;;; (23122 58397 335688 478000))
;;;;;; (23124 14346 925408 142000))
;;; Generated autoloads from discover-my-major.el
(autoload 'discover-my-major "discover-my-major" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "easy-kill" "easy-kill.el" (23122 58399 145697
;;;;;; 438000))
;;;### (autoloads nil "easy-kill" "easy-kill.el" (23124 14348 445415
;;;;;; 305000))
;;; Generated autoloads from easy-kill.el
(autoload 'easy-kill "easy-kill" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "editorconfig" "editorconfig.el" (23122 58400
;;;;;; 22368 445000))
;;;### (autoloads nil "editorconfig" "editorconfig.el" (23124 14349
;;;;;; 225418 981000))
;;; Generated autoloads from editorconfig.el
(autoload 'editorconfig-find-current-editorconfig "editorconfig" "\
@ -45,7 +45,7 @@ mode is not listed in `editorconfig-exclude-modes'.
;;;***
;;;### (autoloads nil "editorconfig-conf-mode" "editorconfig-conf-mode.el"
;;;;;; (23122 58400 5701 696000))
;;;;;; (23124 14349 205418 887000))
;;; Generated autoloads from editorconfig-conf-mode.el
(autoload 'editorconfig-conf-mode "editorconfig-conf-mode" "\
@ -58,7 +58,7 @@ Major mode for editing .editorconfig files.
;;;***
;;;### (autoloads nil "editorconfig-core" "editorconfig-core.el"
;;;;;; (23122 58399 999034 996000))
;;;;;; (23124 14349 198752 189000))
;;; Generated autoloads from editorconfig-core.el
(autoload 'editorconfig-core-get-nearest-editorconfig "editorconfig-core" "\
@ -91,7 +91,7 @@ hash object instead.
;;;***
;;;### (autoloads nil "editorconfig-fnmatch" "editorconfig-fnmatch.el"
;;;;;; (23122 58399 989034 947000))
;;;;;; (23124 14349 188752 142000))
;;; Generated autoloads from editorconfig-fnmatch.el
(autoload 'editorconfig-fnmatch-p "editorconfig-fnmatch" "\
@ -115,7 +115,7 @@ be used:
;;;***
;;;### (autoloads nil nil ("editorconfig-core-handle.el" "editorconfig-pkg.el")
;;;;;; (23122 58400 29035 145000))
;;;;;; (23124 14349 235419 28000))
;;;***

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "elisp-slime-nav" "elisp-slime-nav.el" (23122
;;;;;; 58437 146626 52000))
;;;### (autoloads nil "elisp-slime-nav" "elisp-slime-nav.el" (23124
;;;;;; 14381 378904 870000))
;;; Generated autoloads from elisp-slime-nav.el
(autoload 'elisp-slime-nav-mode "elisp-slime-nav" "\

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil nil ("epl.el") (23122 58400 822372 404000))
;;;### (autoloads nil nil ("epl.el") (23124 14349 848755 252000))
;;;***

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "expand-region" "expand-region.el" (23122 58401
;;;;;; 666040 856000))
;;;### (autoloads nil "expand-region" "expand-region.el" (23124 14350
;;;;;; 545425 202000))
;;; Generated autoloads from expand-region.el
(autoload 'er/expand-region "expand-region" "\
@ -20,7 +20,7 @@ before calling `er/expand-region' for the first time.
;;;***
;;;### (autoloads nil "expand-region-custom" "expand-region-custom.el"
;;;;;; (23122 58401 819451 579000))
;;;;;; (23124 14350 682092 513000))
;;; Generated autoloads from expand-region-custom.el
(let ((loads (get 'expand-region 'custom-loads))) (if (member '"expand-region-custom" loads) nil (put 'expand-region 'custom-loads (cons '"expand-region-custom" loads))))
@ -88,7 +88,7 @@ If set to nil, always place the cursor at the beginning of the region.")
;;;;;; "python-el-expansions.el" "python-el-fgallina-expansions.el"
;;;;;; "python-mode-expansions.el" "ruby-mode-expansions.el" "sml-mode-expansions.el"
;;;;;; "subword-mode-expansions.el" "text-mode-expansions.el" "the-org-mode-expansions.el"
;;;;;; "web-mode-expansions.el") (23122 58401 882816 877000))
;;;;;; "web-mode-expansions.el") (23124 14350 745426 145000))
;;;***

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "flycheck" "flycheck.el" (23122 58404 230632
;;;;;; 235000))
;;;### (autoloads nil "flycheck" "flycheck.el" (23124 14352 848769
;;;;;; 390000))
;;; Generated autoloads from flycheck.el
(autoload 'flycheck-manual "flycheck" "\
@ -228,7 +228,7 @@ Use this together with the `option', `option-list' and
;;;***
;;;### (autoloads nil nil ("flycheck-buttercup.el" "flycheck-ert.el"
;;;;;; "flycheck-pkg.el") (23122 58404 220627 188000))
;;;;;; "flycheck-pkg.el") (23124 14352 838769 343000))
;;;***

View File

@ -4,7 +4,7 @@
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "forest-blue-theme" "forest-blue-theme.el"
;;;;;; (23122 58889 736302 221000))
;;;;;; (23124 14447 622556 361000))
;;; Generated autoloads from forest-blue-theme.el
(when load-file-name (add-to-list 'custom-theme-load-path (file-name-as-directory (file-name-directory load-file-name))))

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "geiser" "geiser.el" (23122 58448 295449 580000))
;;;### (autoloads nil "geiser" "geiser.el" (23124 14388 708940 75000))
;;; Generated autoloads from geiser.el
(defconst geiser-elisp-dir (file-name-directory load-file-name) "\
@ -113,7 +113,7 @@ Disable Geiser's mode (useful in Scheme buffers)." t)
;;;;;; "geiser-log.el" "geiser-menu.el" "geiser-mit.el" "geiser-mode.el"
;;;;;; "geiser-pkg.el" "geiser-popup.el" "geiser-racket.el" "geiser-reload.el"
;;;;;; "geiser-repl.el" "geiser-syntax.el" "geiser-table.el" "geiser-version.el"
;;;;;; "geiser-xref.el") (23122 58448 658841 405000))
;;;;;; "geiser-xref.el") (23124 14389 55608 407000))
;;;***

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "gh-api" "gh-api.el" (23122 58408 269336 256000))
;;;### (autoloads nil "gh-api" "gh-api.el" (23124 14356 232118 669000))
;;; Generated autoloads from gh-api.el
(require 'eieio)
@ -24,8 +24,8 @@
;;;***
;;;### (autoloads nil "gh-auth" "gh-auth.el" (23122 58408 366051
;;;;;; 711000))
;;;### (autoloads nil "gh-auth" "gh-auth.el" (23124 14356 328785
;;;;;; 791000))
;;; Generated autoloads from gh-auth.el
(require 'eieio)
@ -40,8 +40,8 @@
;;;***
;;;### (autoloads nil "gh-cache" "gh-cache.el" (23122 58408 332701
;;;;;; 554000))
;;;### (autoloads nil "gh-cache" "gh-cache.el" (23124 14356 295452
;;;;;; 300000))
;;; Generated autoloads from gh-cache.el
(require 'eieio)
@ -52,8 +52,8 @@
;;;***
;;;### (autoloads nil "gh-comments" "gh-comments.el" (23122 58408
;;;;;; 225981 52000))
;;;### (autoloads nil "gh-comments" "gh-comments.el" (23124 14356
;;;;;; 188785 131000))
;;; Generated autoloads from gh-comments.el
(require 'eieio)
@ -62,8 +62,8 @@
;;;***
;;;### (autoloads nil "gh-common" "gh-common.el" (23122 58408 296016
;;;;;; 382000))
;;;### (autoloads nil "gh-common" "gh-common.el" (23124 14356 258785
;;;;;; 461000))
;;; Generated autoloads from gh-common.el
(require 'eieio)
@ -88,8 +88,8 @@
;;;***
;;;### (autoloads nil "gh-gist" "gh-gist.el" (23122 58408 242656
;;;;;; 130000))
;;;### (autoloads nil "gh-gist" "gh-gist.el" (23124 14356 205451
;;;;;; 876000))
;;; Generated autoloads from gh-gist.el
(require 'eieio)
@ -111,15 +111,15 @@
;;;***
;;;### (autoloads nil "gh-issue-comments" "gh-issue-comments.el"
;;;;;; (23122 58408 312691 460000))
;;;;;; (23124 14356 275452 206000))
;;; Generated autoloads from gh-issue-comments.el
(require 'eieio)
;;;***
;;;### (autoloads nil "gh-issues" "gh-issues.el" (23122 58408 339371
;;;;;; 586000))
;;;### (autoloads nil "gh-issues" "gh-issues.el" (23124 14356 302118
;;;;;; 998000))
;;; Generated autoloads from gh-issues.el
(require 'eieio)
@ -138,8 +138,8 @@
;;;***
;;;### (autoloads nil "gh-oauth" "gh-oauth.el" (23122 58408 232651
;;;;;; 83000))
;;;### (autoloads nil "gh-oauth" "gh-oauth.el" (23124 14356 198785
;;;;;; 178000))
;;; Generated autoloads from gh-oauth.el
(require 'eieio)
@ -154,8 +154,8 @@
;;;***
;;;### (autoloads nil "gh-orgs" "gh-orgs.el" (23122 58408 306021
;;;;;; 429000))
;;;### (autoloads nil "gh-orgs" "gh-orgs.el" (23124 14356 268785
;;;;;; 508000))
;;; Generated autoloads from gh-orgs.el
(require 'eieio)
@ -170,16 +170,16 @@
;;;***
;;;### (autoloads nil "gh-pull-comments" "gh-pull-comments.el" (23122
;;;;;; 58408 359381 680000))
;;;### (autoloads nil "gh-pull-comments" "gh-pull-comments.el" (23124
;;;;;; 14356 322119 93000))
;;; Generated autoloads from gh-pull-comments.el
(require 'eieio)
;;;***
;;;### (autoloads nil "gh-pulls" "gh-pulls.el" (23122 58408 349376
;;;;;; 633000))
;;;### (autoloads nil "gh-pulls" "gh-pulls.el" (23124 14356 312119
;;;;;; 46000))
;;; Generated autoloads from gh-pulls.el
(require 'eieio)
@ -196,8 +196,8 @@
;;;***
;;;### (autoloads nil "gh-repos" "gh-repos.el" (23122 58408 322696
;;;;;; 507000))
;;;### (autoloads nil "gh-repos" "gh-repos.el" (23124 14356 285452
;;;;;; 253000))
;;; Generated autoloads from gh-repos.el
(require 'eieio)
@ -212,15 +212,15 @@
;;;***
;;;### (autoloads nil "gh-search" "gh-search.el" (23122 58408 252661
;;;;;; 177000))
;;;### (autoloads nil "gh-search" "gh-search.el" (23124 14356 215451
;;;;;; 923000))
;;; Generated autoloads from gh-search.el
(eieio-defclass-autoload 'gh-search-api '(gh-api-v3) "gh-search" nil)
;;;***
;;;### (autoloads nil "gh-url" "gh-url.el" (23122 58408 205970 958000))
;;;### (autoloads nil "gh-url" "gh-url.el" (23124 14356 168785 37000))
;;; Generated autoloads from gh-url.el
(require 'eieio)
@ -233,8 +233,8 @@
;;;***
;;;### (autoloads nil "gh-users" "gh-users.el" (23122 58408 286011
;;;;;; 335000))
;;;### (autoloads nil "gh-users" "gh-users.el" (23124 14356 248785
;;;;;; 414000))
;;; Generated autoloads from gh-users.el
(require 'eieio)
@ -245,8 +245,8 @@
;;;***
;;;### (autoloads nil nil ("gh-pkg.el" "gh-profile.el" "gh.el") (23122
;;;;;; 58408 279341 303000))
;;;### (autoloads nil nil ("gh-pkg.el" "gh-profile.el" "gh.el") (23124
;;;;;; 14356 242118 716000))
;;;***

View File

@ -1,18 +0,0 @@
This is the file .../info/dir, which contains the
topmost node of the Info hierarchy, called (dir)Top.
The first time you invoke Info you start off looking at this node.

File: dir, Node: Top This is the top of the INFO tree
This (the Directory node) gives a menu of major topics.
Typing "q" exits, "?" lists all Info commands, "d" returns here,
"h" gives a primer for first-timers,
"mEmacs<Return>" visits the Emacs manual, etc.
In Emacs, you can click mouse button 2 on a menu item or cross reference
to select it.
* Menu:
Emacs
* Ghub: (ghub). Minuscule client library for the Github API.

View File

@ -1,37 +0,0 @@
;;; ghub-autoloads.el --- automatically extracted autoloads
;;
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "ghub" "ghub.el" (23122 58418 754274 83000))
;;; Generated autoloads from ghub.el
(autoload 'ghub-create-token "ghub" "\
Create, store and return a new token.
HOST is the Github instance, usually \"api.github.com\".
USERNAME is the name of a user on that instance.
PACKAGE is the package that will use the token.
SCOPES are the scopes the token is given access to.
\(fn HOST USERNAME PACKAGE SCOPES)" t nil)
(autoload 'ghub-token-scopes "ghub" "\
Return and echo the scopes of the specified token.
This is intended for debugging purposes only. The user
has to provide several values including their password.
\(fn HOST USERNAME PACKAGE)" t nil)
;;;***
;;;### (autoloads nil nil ("ghub-pkg.el") (23122 58418 770947 582000))
;;;***
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; End:
;;; ghub-autoloads.el ends here

View File

@ -1,8 +0,0 @@
(define-package "ghub" "20171218.1028" "minuscule client library for the Github API"
'((emacs "24.4")
(let-alist "1.0.5"))
:url "https://github.com/magit/ghub" :keywords
'("tools"))
;; Local Variables:
;; no-byte-compile: t
;; End:

View File

@ -1,600 +0,0 @@
;;; ghub.el --- minuscule client library for the Github API -*- lexical-binding: t -*-
;; Copyright (C) 2016-2017 Jonas Bernoulli
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Homepage: https://github.com/magit/ghub
;; Keywords: tools
;; Package-Requires: ((emacs "24.4") (let-alist "1.0.5"))
;; This file is not part of GNU Emacs.
;; This file 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 file 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.
;; For a copy of the GPL see https://www.gnu.org/licenses/gpl.txt.
;;; Commentary:
;; Ghub is a library that provides basic support for using the Github API
;; from Emacs packages. It abstracts access to API resources using only
;; a handful of functions that are not resource-specific.
;; It also handles the creation, storage and use of access tokens using a
;; setup wizard, to make it easier for users to get started and to reduce
;; the support burden imposed on package maintainers. It also comes with
;; a comprehensive manual to address the cases when things don't just
;; work as expected.
;; Ghub is intentionally limited to only provide these two essential
;; features — basic request functions and guided setup — to avoid being
;; too opinionated, which would hinder wide adaption. It is assumed that
;; wide adoption would make life easier for users and maintainers alike,
;; because then all packages that talk to the Github API could be
;; configured the same way.
;;; Code:
(require 'auth-source)
(require 'cl-lib)
(require 'json)
(require 'let-alist)
(require 'url)
(require 'url-auth)
(eval-when-compile (require 'subr-x))
(defvar url-http-end-of-headers)
(defvar url-http-response-status)
;;; Settings
(defconst ghub-default-host "api.github.com")
(defvar ghub-github-token-scopes '(repo)
"The Github API scopes that your private tools need.
The token that is created based on the value of this variable
is used when `ghub-request' (or one of its wrappers) is called
without providing a value for AUTH. Packages should always
identify themselves using that argument, but when you use Ghub
directly in private tools, then that is not necessary and the
request is made on behalf of the `ghub' package itself, aka on
behalf of some private tool.
By default the only requested scope is `repo' because that is
sufficient as well as required for most common uses. This and
other scopes are documented at https://magit.vc/goto/2e586d36.
If your private tools need other scopes, then you have to add
them here *before* creating the token. Alternatively you can
edit the scopes of an existing token using the web interface
at https://github.com/settings/tokens.")
(defvar ghub-override-system-name nil
"If non-nil, the string used to identify the local machine.
If this is nil, then the value returned by `system-name' is
used instead.")
;;; Request
;;;; API
(defvar ghub-response-headers nil
"The headers returned in response to the last request.
`ghub-request' returns the response body and stores the
response header in this variable.")
(defvar ghub-raw-response-body nil)
(cl-defun ghub-head (resource &optional params
&key query payload headers
unpaginate noerror reader
username auth host)
"Make a `HEAD' request for RESOURCE, with optional query PARAMS.
Like calling `ghub-request' (which see) with \"HEAD\" as METHOD."
(ghub-request "HEAD" resource params
:query query :payload payload :headers headers
:unpaginate unpaginate :noerror noerror :reader reader
:username username :auth auth :host host))
(cl-defun ghub-get (resource &optional params
&key query payload headers
unpaginate noerror reader
username auth host)
"Make a `GET' request for RESOURCE, with optional query PARAMS.
Like calling `ghub-request' (which see) with \"GET\" as METHOD."
(ghub-request "GET" resource params
:query query :payload payload :headers headers
:unpaginate unpaginate :noerror noerror :reader reader
:username username :auth auth :host host))
(cl-defun ghub-put (resource &optional params
&key query payload headers
unpaginate noerror reader
username auth host)
"Make a `PUT' request for RESOURCE, with optional payload PARAMS.
Like calling `ghub-request' (which see) with \"PUT\" as METHOD."
(ghub-request "PUT" resource params
:query query :payload payload :headers headers
:unpaginate unpaginate :noerror noerror :reader reader
:username username :auth auth :host host))
(cl-defun ghub-post (resource &optional params
&key query payload headers
unpaginate noerror reader
username auth host)
"Make a `POST' request for RESOURCE, with optional payload PARAMS.
Like calling `ghub-request' (which see) with \"POST\" as METHOD."
(ghub-request "POST" resource params
:query query :payload payload :headers headers
:unpaginate unpaginate :noerror noerror :reader reader
:username username :auth auth :host host))
(cl-defun ghub-patch (resource &optional params
&key query payload headers
unpaginate noerror reader
username auth host)
"Make a `PATCH' request for RESOURCE, with optional payload PARAMS.
Like calling `ghub-request' (which see) with \"PATCH\" as METHOD."
(ghub-request "PATCH" resource params
:query query :payload payload :headers headers
:unpaginate unpaginate :noerror noerror :reader reader
:username username :auth auth :host host))
(cl-defun ghub-delete (resource &optional params
&key query payload headers
unpaginate noerror reader
username auth host)
"Make a `DELETE' request for RESOURCE, with optional payload PARAMS.
Like calling `ghub-request' (which see) with \"DELETE\" as METHOD."
(ghub-request "DELETE" resource params
:query query :payload payload :headers headers
:unpaginate unpaginate :noerror noerror :reader reader
:username username :auth auth :host host))
(define-error 'ghub-error "Ghub Error")
(define-error 'ghub-http-error "HTTP Error" 'ghub-error)
(define-error 'ghub-301 "Moved Permanently" 'ghub-http-error)
(define-error 'ghub-400 "Bad Request" 'ghub-http-error)
(define-error 'ghub-401 "Unauthorized" 'ghub-http-error)
(define-error 'ghub-403 "Forbidden" 'ghub-http-error)
(define-error 'ghub-404 "Not Found" 'ghub-http-error)
(define-error 'ghub-422 "Unprocessable Entity" 'ghub-http-error)
(define-error 'ghub-500 "Internal Server Error" 'ghub-http-error)
(cl-defun ghub-request (method resource &optional params
&key query payload headers
unpaginate noerror reader
username auth host)
"Make a request for RESOURCE and return the response body.
Also place the response header in `ghub-response-headers'.
METHOD is the http method, given as a string.
RESOURCE is the resource to access, given as a string beginning
with a slash.
PARAMS, QUERY, PAYLOAD and HEADERS are alists used to specify
data. The Github API documentation is vague on how data has
to be transmitted and for a particular resource usually just
talks about \"parameters\". Generally speaking when the METHOD
is \"HEAD\" or \"GET\", then they have to be transmitted as a
query, otherwise as a payload.
Use PARAMS to automatically transmit like QUERY or PAYLOAD would
depending on METHOD.
Use QUERY to explicitly transmit data as a query.
Use PAYLOAD to explicitly transmit data as a payload.
Use HEADERS for those rare resources that require that the data
is transmitted as headers instead of as a query or payload.
When that is the case, then the api documentation usually
mentions it explicitly.
If UNPAGINATE is non-nil, then make multiple requests if necessary
to get all items at RESOURCE.
If NOERROR is non-nil, then do not raise an error if the request
fails and return nil instead.
If READER is non-nil, then it is used to read and return from the
response buffer. The default is `ghub--read-json-response'.
For the very few resources that do not return json, you might
want to use `ghub--read-raw-response'.
If USERNAME is non-nil, then make a request on behalf of that
user. It is better to specify the user using the Git variable
`github.user' for \"api.github.com\", or `github.HOST.user' if
connecting to a Github Enterprise instance.
Each package that uses `ghub' should use its own token. If AUTH
is nil, then the generic `ghub' token is used instead. This
is only acceptable for personal utilities. A packages that
is distributed to other users should always use this argument
to identify itself, using a symbol matching its name.
Package authors who find this inconvenient should write a
wrapper around this function and possibly for the method
specific functions also.
Some symbols have a special meaning. `none' means to make an
unauthorized request. `basic' means to make a password based
request. If the value is a string, then it is assumed to be
a valid token. `basic' and an explicit token string are only
intended for internal and debugging uses.
If AUTH is a package symbol, then the scopes are specified
using the variable `AUTH-github-token-scopes'. It is an error
if that is not specified. See `ghub-github-token-scopes' for
an example.
If HOST is non-nil, then connect to that Github instance. This
defaults to \"api.github.com\". When a repository is connected
to a Github Enterprise instance, then it is better to specify
that using the Git variable `github.host' instead of using this
argument."
(unless (string-prefix-p "/" resource)
(setq resource (concat "/" resource)))
(unless host
(setq host (ghub--host)))
(cond
((not params))
((memq method '("GET" "HEAD"))
(when query
(error "PARAMS and QUERY are mutually exclusive for METHOD %S" method))
(setq query params))
(t
(when payload
(error "PARAMS and PAYLOAD are mutually exclusive for METHOD %S" method))
(setq payload params)))
(when (and payload (not (stringp payload)))
(setq payload (encode-coding-string (json-encode-list payload) 'utf-8)))
(let* ((qry (and query (concat "?" (ghub--url-encode-params query))))
(buf (let ((url-request-extra-headers
`(("Content-Type" . "application/json")
,@(and (not (eq auth 'none))
(list (cons "Authorization"
(ghub--auth host auth username))))
,@headers))
;; Encode in case caller used (symbol-name 'GET). #35
(url-request-method (encode-coding-string method 'utf-8))
(url-request-data payload))
(url-retrieve-synchronously
(concat "https://" host resource qry)))))
(unwind-protect
(with-current-buffer buf
(set-buffer-multibyte t)
(let (link body)
(goto-char (point-min))
(let (headers)
(while (re-search-forward "^\\([^:]*\\): \\(.+\\)"
url-http-end-of-headers t)
(push (cons (match-string 1)
(match-string 2))
headers))
(and (setq link (cdr (assoc "Link" headers)))
(setq link (car (rassoc
(list "rel=\"next\"")
(mapcar (lambda (elt) (split-string elt "; "))
(split-string link ",")))))
(string-match "[?&]page=\\([^&>]+\\)" link)
(setq link (match-string 1 link)))
(setq ghub-response-headers (nreverse headers)))
(unless url-http-end-of-headers
(error "ghub: url-http-end-of-headers is nil when it shouldn't"))
(goto-char (1+ url-http-end-of-headers))
(setq body (funcall (or reader 'ghub--read-json-response)
url-http-response-status))
(unless (or noerror (= (/ url-http-response-status 100) 2))
(let ((data (list method resource qry payload body)))
(pcase url-http-response-status
(301 (signal 'ghub-301 data))
(400 (signal 'ghub-400 data))
(401 (signal 'ghub-401 data))
(403 (signal 'ghub-403 data))
(404 (signal 'ghub-404 data))
(422 (signal 'ghub-422 data))
(500 (signal 'ghub-500 data))
(_ (signal 'ghub-http-error
(cons url-http-response-status data))))))
(if (and link unpaginate)
(nconc body
(ghub-request
method resource nil
:query (cons (cons 'page link)
(cl-delete 'page query :key #'car))
:payload payload
:headers headers
:unpaginate t :noerror noerror :reader reader
:username username :auth auth :host host))
body)))
(kill-buffer buf))))
(defun ghub-wait (resource &optional username auth host duration)
"Busy-wait up to DURATION seconds for RESOURCE to become available.
DURATION specifies how many seconds to wait at most. It defaults
to 64 seconds. The first attempt is made immediately, the second
after two seconds, and each subequent attemts are made after
waiting as long as we already waited between all preceding
attempts combined.
See `ghub-request' for information about the other arguments."
(unless duration
(setq duration 64))
(with-local-quit
(let ((total 0))
(while (not (ignore-errors (ghub-get resource nil
:username username
:auth auth
:host host)))
(message "Waited (%3ss of %ss) for %s..." total duration resource)
(if (= total duration)
(signal 'ghub-error
(list (format "Github is taking too long to create %s"
resource)))
(if (> total 0)
(let ((wait (min total (- duration total))))
(sit-for wait)
(cl-incf total wait))
(sit-for (setq total 2))))))))
;;;; Internal
(defun ghub--read-json-response (status)
(let ((raw (ghub--read-raw-response)))
(and raw
(condition-case nil
(let ((json-object-type 'alist)
(json-array-type 'list)
(json-key-type 'symbol)
(json-false nil)
(json-null nil))
(json-read-from-string raw))
(json-readable-error
(ghub--handle-invalid-response status raw))))))
(defun ghub--read-raw-response (&optional _status)
(and (not (eobp))
(setq ghub-raw-response-body
(decode-coding-string
(buffer-substring-no-properties (point) (point-max))
'utf-8))))
(defun ghub--handle-invalid-response (status body)
(let ((html-p (string-prefix-p "<!DOCTYPE html>" body))
content)
(when html-p
(with-temp-buffer
(save-excursion (insert body))
(while (re-search-forward "<p>\\(?:<strong>\\)?\\([^<]+\\)" nil t)
(push (match-string 1) content)))
(when content
(setq content (mapconcat #'identity (reverse content) " "))))
`((http_status . ,status)
(invalid_response . "Github failed to deliver Json.")
(invalid_is_html . ,html-p)
(invalid_comment . "Message consists of strings found in the html.")
(message . ,content))))
(defun ghub--url-encode-params (params)
(mapconcat (lambda (param)
(concat (url-hexify-string (symbol-name (car param))) "="
(url-hexify-string (cdr param))))
params "&"))
;;; Authentication
;;;; API
;;;###autoload
(defun ghub-create-token (host username package scopes)
"Create, store and return a new token.
HOST is the Github instance, usually \"api.github.com\".
USERNAME is the name of a user on that instance.
PACKAGE is the package that will use the token.
SCOPES are the scopes the token is given access to."
(interactive
(pcase-let ((`(,host ,username ,package)
(ghub--read-triplet)))
(list host username package
(split-string
(read-string
"Scopes (separated by commas): "
(mapconcat #'symbol-name
(symbol-value
(intern (format "%s-github-token-scopes" package)))
","))
"," t "[\s\t]+"))))
(let ((user (ghub--ident username package)))
(cl-destructuring-bind (_save token)
(ghub--auth-source-get (list :save-function :secret)
:create t :host host :user user
:secret
(cdr (assq 'token
(ghub-post
"/authorizations"
`((scopes . ,scopes)
(note . ,(ghub--ident-github package)))
:username username :auth 'basic :host host))))
;; If the Auth-Source cache contains the information that there
;; is no value, then setting the value does not invalidate that
;; now incorrect information.
(auth-source-forget (list :host host :user user))
token)))
;;;###autoload
(defun ghub-token-scopes (host username package)
"Return and echo the scopes of the specified token.
This is intended for debugging purposes only. The user
has to provide several values including their password."
(interactive (ghub--read-triplet))
(let ((scopes
(cdr (assq 'scopes (ghub--get-token-plist host username package)))))
(when (called-interactively-p 'any)
;; Also show the input values to make it easy for package
;; authors to verify that the user has done it correctly.
(message "Scopes for %s@%s: %S"
(ghub--ident username package)
host scopes))
scopes))
;;;; Internal
(defun ghub--auth (host auth &optional username)
(unless username
(setq username (ghub--username host)))
(if (eq auth 'basic)
(ghub--basic-auth host username)
(concat "token "
(encode-coding-string
(cl-typecase auth
(string auth)
(null (ghub--token host username 'ghub))
(symbol (ghub--token host username auth))
(t (signal 'wrong-type-argument
`((or stringp symbolp) ,auth))))
'utf-8))))
(defun ghub--basic-auth (host username)
(let ((url (url-generic-parse-url (concat "https://" host))))
(setf (url-user url) username)
(url-basic-auth url t)))
(defun ghub--token (host username package &optional nocreate)
(let ((user (ghub--ident username package)))
(or (ghub--auth-source-get :secret :host host :user user)
(progn
;; Auth-Source caches the information that there is no
;; value, but in our case that is a situation that needs
;; fixing so we want to keep trying by invalidating that
;; information. The (:max 1) is needed for Emacs releases
;; before 26.1.
(auth-source-forget (list :max 1 :host host :user
user))
(and (not nocreate)
(ghub--confirm-create-token host username package))))))
(defun ghub--host ()
(or (ignore-errors (car (process-lines "git" "config" "github.host")))
ghub-default-host))
(defun ghub--username (host)
(let ((var (if (string-prefix-p "api.github.com" host)
"github.user"
(format "github.%s.user" host))))
(condition-case nil
(car (process-lines "git" "config" var))
(error
(let ((user (read-string
(format "Git variable `%s' is unset. Set to: " var))))
(or (and user (progn (call-process "git" nil nil nil
"config" "--global" var user)
user))
(user-error "Abort")))))))
(defun ghub--ident (username package)
(format "%s^%s" username package))
(defun ghub--ident-github (package)
(format "Emacs package %s @ %s"
package
(or ghub-override-system-name (system-name))))
(defun ghub--package-scopes (package)
(symbol-value (intern (format "%s-github-token-scopes" package))))
(defun ghub--confirm-create-token (host username package)
(let* ((ident (ghub--ident-github package))
(scopes (ghub--package-scopes package))
(max-mini-window-height 40))
(if (let ((message-log-max nil))
(yes-or-no-p
(format
"Such a Github API token is not available:
Host: %s
User: %s
Package: %s
Scopes requested in `%s-github-token-scopes':\n%s
Store locally according to `auth-sources':\n %S
Store on Github as:\n %S
WARNING: If you have enabled two-factor authentication then
you have to abort and create the token manually.
If in doubt, then abort and view the documentation first.
Otherwise confirm and then provide your Github username and
password at the next two prompts. Depending on the backend
you might have to provide a passphrase and confirm that you
really want to save the token.
Create and store such a token? "
host username package package
(mapconcat (lambda (scope) (format " %s" scope)) scopes "\n")
auth-sources ident)))
(progn
(when (ghub--get-token-id host username package)
(if (yes-or-no-p
(format
"A token named %S\nalready exists on Github. Replace it?"
ident))
(ghub--delete-token host username package)
(user-error "Abort")))
(ghub-create-token host username package scopes))
(user-error "Abort"))))
(defun ghub--get-token-id (host username package)
(let ((ident (ghub--ident-github package)))
(cl-some (lambda (x)
(let-alist x
(and (equal .app.name ident) .id)))
(ghub-get "/authorizations" nil
:unpaginate t
:username username :auth 'basic :host host))))
(defun ghub--get-token-plist (host username package)
(ghub-get (format "/authorizations/%s"
(ghub--get-token-id host username package))
nil :username username :auth 'basic :host host))
(defun ghub--delete-token (host username package)
(ghub-delete (format "/authorizations/%s"
(ghub--get-token-id host username package))
nil :username username :auth 'basic :host host))
(defun ghub--read-triplet ()
(let ((host (read-string "Host: " (ghub--host))))
(list host
(read-string "Username: " (ghub--username host))
(intern (read-string "Package: " "ghub")))))
(defun ghub--auth-source-get (key:s &rest spec)
(declare (indent 1))
(let ((plist (car (apply #'auth-source-search :max 1 spec))))
(cl-flet ((value (k) (let ((v (plist-get plist k)))
(if (functionp v) (funcall v) v))))
(if (listp key:s)
(mapcar #'value key:s)
(value key:s)))))
(advice-add 'auth-source-netrc-parse-next-interesting :around
'auth-source-netrc-parse-next-interesting@save-match-data)
(defun auth-source-netrc-parse-next-interesting@save-match-data (fn)
"Save match-data for the benefit of caller `auth-source-netrc-parse-one'.
Without wrapping this function in `save-match-data' the caller
won't see the secret from a line that is followed by a commented
line."
(save-match-data (funcall fn)))
;;; ghub.el ends soon
(provide 'ghub)
;; Local Variables:
;; indent-tabs-mode: nil
;; End:
;;; ghub.el ends here

View File

@ -1,865 +0,0 @@
This is ghub.info, produced by makeinfo version 5.2 from ghub.texi.
Copyright (C) 2017 Jonas Bernoulli <jonas@bernoul.li>
You can redistribute this document and/or modify it under the terms
of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version.
This document 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.
INFO-DIR-SECTION Emacs
START-INFO-DIR-ENTRY
* Ghub: (ghub). Minuscule client library for the Github API.
END-INFO-DIR-ENTRY

File: ghub.info, Node: Top, Next: Introduction, Up: (dir)
Ghub User and Developer Manual
******************************
Ghub is a library that provides basic support for using the Github API
from Emacs packages. It abstracts access to API resources using only a
handful of functions that are not resource-specific.
It also handles the creation, storage and use of access tokens using
a setup wizard, to make it easier for users to get started and to reduce
the support burden imposed on package maintainers. It also comes with a
comprehensive manual to address the cases when things dont just work as
expected.
Ghub is intentionally limited to only provide these two essential
features — basic request functions and guided setup — to avoid being too
opinionated, which would hinder wide adaption. It is assumed that wide
adoption would make life easier for users and maintainers alike, because
then all packages that talk to the Github API could be configured the
same way.
This manual is for Ghub version 1.3.0 (v1.3.0-31-g6443c4f+1).
Copyright (C) 2017 Jonas Bernoulli <jonas@bernoul.li>
You can redistribute this document and/or modify it under the terms
of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version.
This document 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.
* Menu:
* Introduction::
* Limitations::
* Getting Started::
* Using Ghub in Personal Scripts::
* Using Ghub in a Package::
* API::
— The Detailed Node Listing —
Getting Started
* Setting the Username::
* Interactively Creating and Storing a Token::
* Manually Creating and Storing a Token::
* How Ghub uses Auth-Source::
API
* Making Requests::
* Authentication::
* Configuration Variables::

File: ghub.info, Node: Introduction, Next: Limitations, Prev: Top, Up: Top
1 Introduction
**************
Ghub is a library that provides basic support for using the Github API
from Emacs packages. It abstracts access to API resources using only a
handful of functions that are not resource-specific.
It also handles the creation, storage and use of access tokens using
a setup wizard, to make it easier for users to get started and to reduce
the support burden imposed on package maintainers. It also comes with a
comprehensive manual to address the cases when things dont just work as
expected.
Ghub is intentionally limited to only provide these two essential
features — basic request functions and guided setup — to avoid being too
opinionated, which would hinder wide adaption.
Fancier interfaces can implemented on top of Ghub, and one such
wrapper — named simply Ghub+ — has already been implemented. The
benefit of basing various opinionated interfaces on top of a single
library that provides only the core functionality is that choosing the
programming interface does no longer also dictate how access tokens are
handled. Users can then use multiple packages that access the Github
API without having to learn the various incompatible ways packages
expects the appropriate token to be made available to them.
Ghub uses the built-in auth-source library to store access tokens.
That library is very flexible and supports multiple backends, which
means that it is up to the user how secrets are stored. They can, among
other things, choose between storing secrets in plain text for ease of
use, or encrypted for better security.
Previously (as in until this library is widely adapted) it was up to
package authors to decide if things should be easy or secure. (Note
that auth-source defaults to "easy" — you have been warned.)
Ghub expects package authors to use a dedicated access token instead
of sharing a single token between all packages that rely on it. That
means that users cannot configure Ghub once and later start using a new
package without any additional setup. But Ghub helps with that.
When the user invokes some command defined in some package and that
ultimately results in ghub-request being called and the appropriate
token is not available yet, then the user is guided through the process
of creating and storing a new token, and at the end of that process the
request is carried out as if the token had been available to begin with.

File: ghub.info, Node: Limitations, Next: Getting Started, Prev: Introduction, Up: Top
2 Limitations
*************
As mentioned, Ghub restricts itself to provide core functionality and
leaves it to other libraries to do opinionated things on top of that.
But currently there also are some limitations that concern the core
parts. Obviously these limitations have to be lifted to maximize
adaption and so they will.
These secondary features already exist (just mentioning them, so you
dont assume that they dont):
• Support for Github Enterprise instances.
• Support for token scope validation.
These features will likely never be implemented in Ghub:
• Functions for particular resources.
• Using something other than json-like alists to handle what the
Github API calls "parameters".
• Retrieving an existing token. Github does not support it so we
cannot do it. If you lose your local copy of a token, then you
have to replace it with a new one.
These features are not supported yet:
• Asynchronous requests are not supported yet.
• The Github GraphQL API is not supported yet.
• If a request fails due to a missing scope, then that isnt handled
by ghub-request yet. For now package authors just have to hope
that users dont mess with scopes or handle such errors themselves.
Likewise, other errors too should be handled by Ghub.
• Packages cannot request additional scopes.
Once a token has been created a package cannot request new scopes
that it previously did not need. I am not quite sure yet whether
Ghub should support that. An alternative would be to let packages
at least invalidate their own tokens.
• Other Git forges (Gitlab, Bitbucket…) are not supported.
Support for other forges will likely be implemented using *other*
libraries that are very similar to this library. Whether common
code will be factored out into a library to be used by all these
libraries or whether some code duplication is to be preferred, has
not been decided yet.

File: ghub.info, Node: Getting Started, Next: Using Ghub in Personal Scripts, Prev: Limitations, Up: Top
3 Getting Started
*****************
If you would like to use a package that uses this library, then just do
so. If the necessary information isnt available when it attempts to
make a request, then you will be asked to provide it.
* Menu:
* Setting the Username::
* Interactively Creating and Storing a Token::
* Manually Creating and Storing a Token::
* How Ghub uses Auth-Source::

File: ghub.info, Node: Setting the Username, Next: Interactively Creating and Storing a Token, Up: Getting Started
3.1 Setting the Username
========================
If you havent set the Git variable github.user yet when making a
request, then you will be asked:
Git variable `github.user' is unset. Set to:
You are expected to provide your Github username here. The provided
value will be saved globally (using git config --global github.user
USERNAME).
If you need to identify as another user in a particular repository,
then you have to set that variable locally, *before* making a request:
cd /path/to/repo
git config github.user USERNAME
For Github Enterprise instances you have to specify where the API can
be accessed *before* you try to access it and a different variable has
to be used to set the username. For example if the API is available at
https://example.com/api/v3, then you should do this:
# Do this once
git config --global github.example.com/api/v3.user EMPLOYEE
# Do this for every corporate repository
cd /path/to/repo
git config github.host example.com/api/v3
If you do not set github.example.com/api/v3.user, then you will be
asked to provide the value when trying to make a request, but you do
have to manually set github.host, or Ghub assumes that you are trying
to access api.github.com.

File: ghub.info, Node: Interactively Creating and Storing a Token, Next: Manually Creating and Storing a Token, Prev: Setting the Username, Up: Getting Started
3.2 Interactively Creating and Storing a Token
==============================================
Ghub uses a different token for every package as well as for every
machine from which you access the Github API (and obviously also for
every Github instance and user). This allows packages to only request
the scopes that they actually need and also gives users the opportunity
to refuse access to certain scopes if they expect to not use the
features that need them.
Usually you dont have to worry about creating and storing a token
yourself and can just make a request. Note however that you dont have
to use the setup wizard described below. Alternatively you can perform
the setup manually as described in the next section.
Unfortunately the wizard does not work (yet?) if you have enabled
two-factor authentication, in which case the token has to be created and
stored manually.
If you make a request and the required token is not available yet,
then the setup wizard will first ask you something like this:
Such a Github API token is not available:
Host: api.github.com
User: USERNAME
Package: PACKAGE
Scopes requested in `PACKAGE-github-token-scopes':
repo
Store locally according to `auth-sources':
("~/.authinfo" "~/.authinfo.gpg" "~/.netrc")
Store on Github as:
"Emacs package FOO @ LOCAL-MACHINE"
WARNING: If you have enabled two-factor authentication
then you have to create the token manually.
If in doubt, then abort and view the documentation first.
Create and store such a token? (yes or no)
If you dont have any doubts, then answer "yes". Lets address some
of the doubts that you might have:
• Unfortunately Ghub cannot know whether you have enabled two-factor
authentication without making a request using basic (password)
authentication, which it cannot do if you have enabled two-factor
authentication. It also cannot determine whether you have enabled
two-factor authentication depending on whether a request fails or
not because there are other reasons why a request might fail.
So this warning is always displayed and you are expected to know
whether you have enabled two-factor authentication or not. If you
have, then you must abort and see *note Manually Creating and
Storing a Token::.
Host usually is "api.github.com" and thats usually what you
want. If you are trying to access a Github Enterprise instance,
then it should be something else and you have to set the value
manually as described in the next section.
User should be your Github.com (or Github Enterprise instance)
username. If it is something else, then you made a mistake at the
first prompt or during the step describe in the previous section
and have to refer to that in order to fix this issue.
Package should be the name of the package you are using to access
the Github API.
If it is ghub, then the package author disregarded that
convention and you should probably report a bug in the issue
tracker of that package.
Or you yourself are using ghub-request or one of its wrappers
directly, in which case this is expected and perfectly fine. In
that case you might however want to abort and change the value of
the variable ghub-github-token-scopes before triggering the
wizard again.
• Each PACKAGE has to specify the tokens that it needs using a
variable named PACKAGE-github-token-scopes. The doc-string of
that variable should document why the various scopes are needed.
The meaning of the various scopes are documented at
<https://magit.vc/goto/f63aeb0a>.
• The value of auth-sources is shown. The default value causes
secrets to be stored in plain text. Because this might be
unexpected, Ghub additionally displays a warning when appropriate.
WARNING: ... unencrypted ... TODO implement ...
Whether that is something that needs fixing, is up to you. If your
answer is yes, then you should abort and see *note How Ghub uses
Auth-Source:: for instructions on how to save the token more
securely.
• When creating a token it is necessary to provide a token
description. Ghub used descriptions that have the form "Emacs
package PACKAGE @ LOCAL-MACHINE".
Github uses the token description to identify the token, not merely
as something useful to humans. Token descriptions therefore have
to be unique and in rare cases you get an additional prompt, asking
you something like:
A token named "Emacs package FOO @ LOCAL-MACHINE"
already exists on Github. Replace it?
You might see this message when you have lost the old token and
want to replace it with a new one, in which case you should
obviously just proceed.
Or two of your computers have the same hostname, which is bad
practice because it gains you nothing but leads to issues such as
this. Or you are dual-booting on this machine and use the same
hostname in all operating systems, which is a somewhat reasonable
thing to do.
In either case you will have to use something other than the value
returned by system-name to identify the current machine or
operating system. Or you can continue to identify different things
using the same identifier, in which case you have to manually
distribute the token.
The former is recommended and also easier to do, using the variable
ghub-override-system-name. See *note Configuration Variables::
for details.

File: ghub.info, Node: Manually Creating and Storing a Token, Next: How Ghub uses Auth-Source, Prev: Interactively Creating and Storing a Token, Up: Getting Started
3.3 Manually Creating and Storing a Token
=========================================
If you have enabled two-factor authentication, then you have to create
and store access tokens yourself. You might also prefers to always do
it manually to have more control than when relying on the setup wizard.
If you cannot or dont want to use the wizard then you have to (1)
figure out what scopes a package wants, (2) create such a token using
the web interface and (3) store the token where Ghub expects to find it.
A package named PACKAGE has to specify the scopes that it wants in
the variable named PACKAGE-ghub-token-scopes. The doc-string of such
variables should document what the various scopes are needed for.
To create or edit a token go to <https://github.com/settings/tokens>.
Finally store the token in a place where Ghub looks for it as
describe in *note How Ghub uses Auth-Source::.

File: ghub.info, Node: How Ghub uses Auth-Source, Prev: Manually Creating and Storing a Token, Up: Getting Started
3.4 How Ghub uses Auth-Source
=============================
Please see *note (auth)Top:: for all the gory details about Auth-Source.
Some Ghub-specific information and important notes follow.
The variable auth-sources controls how and where Auth-Source stores
new secrets and where it looks for known secrets. The default value is
("~/.authinfo" "~/.authinfo.gpg" "~/.netrc"), which means that it
looks in all of these files in order to find secrets and that it stores
new secrets in ~/.authinfo because that is the first element of the
list. It doesnt matter which files already do or dont exist when
storing a new secret, the first file is always used.
Secrets are stored in ~/.authinfo in plain text. If you dont want
that (good choice), then you have to customize auth-sources e.g. by
flipping the positions of the first two elements.
Auth-Source also supports storing secrets in various key-chains,
refer to its documentation for more information.
Some Auth-Source backends only support storing three values per
entry, the "machine", the "login" and the "password". Because Ghub uses
separate tokens for each package, it has to squeeze four values into
those three slots, and it does that by using "USERNAME^PACKAGE" as the
"login".
Assuming your username is "ziggy" and the package is named
"stardust", an entry in one of the three mentioned files would then look
like this:
machine api.github.com login ziggy^stardust password 012345abcdef...

File: ghub.info, Node: Using Ghub in Personal Scripts, Next: Using Ghub in a Package, Prev: Getting Started, Up: Top
4 Using Ghub in Personal Scripts
********************************
You can use ghub-request and its wrapper functions in your personal
scripts of course. Unlike when you use Ghub from a package that you
distribute for others to use, you dont have to specify a package in
personal scripts.
;; This is perfectly acceptable in personal scripts ...
(ghub-get "/user")
;; ... and actually equal to
(ghub-get "/user" nil :auth 'ghub)
;; In packages you have to specify the package using AUTH.
(ghub-get "/user" nil :auth 'foobar)
When you do not specify the AUTH argument, then a request is made on
behalf of the ghub package itself. Like for any package that uses
Ghub, ghub has to declare what scopes it needs, using, in this case,
the variable ghub-github-token-scopes.
The default value of that variable is (repo) and you might want to
add additional scopes. You can later add additional scopes to an
existing token, using the web interface at
<https://github.com/settings/tokens>.
If you do that, then you might want to also set the variable
accordingly, but note that Ghub only consults that when *creating* a new
token. If you want to know a tokens effective scopes use the command
ghub-token-scopes, described in the next section.

File: ghub.info, Node: Using Ghub in a Package, Next: API, Prev: Using Ghub in Personal Scripts, Up: Top
5 Using Ghub in a Package
*************************
Every package should use its own token. This allows you as the author
of some package to only request access to API scopes that are actually
needed, which in turn might make it easier for users to trust your
package not to do unwanted things.
The scopes used by PACKAGE have to be defined using the variable
PACKAGE-github-token-scopes, and you have to tell ghub-request on
behalf of what package a request is being made by passing the symbol
PACKAGE as the value of its AUTH argument.
(ghub-request "GET" "/user" nil :auth 'PACKAGE)
-- Variable: PACKAGE-github-token-scopes
This variable defines the token scopes requested by the package
named PACKAGE. The doc-string should explain what the various
scopes are needed for to prevent users from giving PACKAGE fewer
permissions than it absolutely needs and also to give them greater
confidence that PACKAGE is only requesting the permissions that it
actually need.
The value of this variable does not necessarily correspond to the
scopes that the respective token actually gives access to. There
is nothing that prevents users from changing the value *after*
creating the token or from editing the tokens scopes later on.
So it is pointless to check the value of this variable before
making a request. You also should not query the API to reliably
determine the supported tokens before making a query. Doing the
latter would mean that every request becomes two requests and that
the first request would have to be done using the users password
instead of a token.
-- Command: ghub-token-scopes
Because we cannot be certain that the user hasnt messed up the
scopes, Ghub provides this command to make it easy to debug such
issues without having to rely on users being thoughtful enough to
correctly determine the used scopes manually.
Just tell users to run M-x ghub-token-scopes and to provide the
correct values for the HOST, USERNAME and PACKAGE when prompted,
and to then post the output.
It is to be expected that users will occasionally mess that up so
this command does not only output the scopes but also the user
input so that you can have greater confidence in the validity of
the users answer.
Scopes for USERNAME^PACKAGE@HOST: (SCOPE...)

File: ghub.info, Node: API, Prev: Using Ghub in a Package, Up: Top
6 API
*****
This section describes the Ghub API. In other words it describes the
public functions and variables provided by the Ghub library and not the
Github API that can be accessed by using those functions. The latter is
documented at <https://developer.github.com/v3>.
* Menu:
* Making Requests::
* Authentication::
* Configuration Variables::

File: ghub.info, Node: Making Requests, Next: Authentication, Up: API
6.1 Making Requests
===================
-- Function: ghub-request method resource &optional params &key query
payload headers unpaginate noerror reader username auth host
This function make a request for RESOURCE using METHOD. PARAMS,
QUERY, PAYLOAD and/or HEADERS are alists holding additional request
data. The response body is returned and the response header in
stored in the variable ghub-response-headers.
• METHOD is the http method, given as a string.
• RESOURCE is the resource to access, given as a string
beginning with a slash.
• PARAMS, QUERY, PAYLOAD and HEADERS are alists and are used to
specify request data. All these arguments are alists that
resemble the Json expected and returned by the Github API. The
keys are symbols and the values are stored in the cdr (not
the cadr) and can be strings, integers and lists of strings
and integers.
The Github API documentation is vague on how data has to be
transmitted and for a particular resource usually just talks
about "parameters". Generally speaking when the METHOD is
"HEAD" or "GET", then they have to be transmitted as a query,
otherwise as a payload.
• Use PARAMS to automatically transmit like QUERY or
PAYLOAD would depending on METHOD.
• Use QUERY to explicitly transmit data as a query.
• Use PAYLOAD to explicitly transmit data as a payload.
• Use HEADERS for those rare resources that require that
the data is transmitted as headers instead of as a query
or payload. When that is the case, then the Github API
documentation usually mentions it explicitly.
• If UNPAGINATE is non-nil, then this function makes multiple
requests if necessary to get all items at RESOURCE.
• If NOERROR is non-nil, then no error is raised if the request
fails and nil is returned instead.
• If READER is non-nil, then it is used to read and return from
the response buffer. The default is
ghub--read-json-response. For the very few resources that
do not return json, you might want to use
ghub--read-raw-response.
• If USERNAME is non-nil, then the request is made on behalf of
that user. It is better to specify the user using the Git
variable github.user for "api.github.com", or
github.HOST.user if connecting to a Github Enterprise
instance.
• Each package that uses Ghub should use its own token. If AUTH
is nil, then the generic ghub token is used instead. This
is only acceptable for personal utilities. A packages that is
distributed to other users should always use this argument to
identify itself, using a symbol matching its name.
Package authors who find this inconvenient should write a
wrapper around this function and possibly for the method
specific functions also.
Some symbols have a special meaning. none means to make an
unauthorized request. basic means to make a password based
request. If the value is a string, then it is assumed to be a
valid token. basic and an explicit token string are only
intended for internal and debugging uses.
If AUTH is a package symbol, then the scopes are specified
using the variable AUTH-github-token-scopes. It is an error
if that is not specified. See ghub-github-token-scopes for
an example.
• If HOST is non-nil, then connect to that Github instance.
This defaults to "api.github.com". When a repository is
connected to a Github Enterprise instance, then it is better
to specify that using the Git variable github.host instead
of using this argument.
-- Variable: ghub-response-headers
A select few Github API resources respond by transmitting data in
the response header instead of in the response body. Because there
are so few of these inconsistencies ghub-request always returns
the response body.
To access the response header use this variable after
ghub-request has returned.
-- Variable: ghub-override-system-name
If non-nil, the value of this variable is used to override the
value returned by system-name for the purpose of identifying the
local machine, which is necessary because Ghub uses separate tokens
for each machine. Also see *note Configuration Variables::.
-- Variable: ghub-github-token-scopes
-- Variable: PACKAGE-github-token-scopes
Such a variable define the token scopes requested by the respective
package PACKAGE given by the first word in the variable name.
ghub itself is treated like any other package. Also see *note
Using Ghub in a Package::.
-- Function: ghub-head resource &optional params &key query payload
headers unpaginate noerror reader username auth host
-- Function: ghub-get resource &optional params &key query payload
headers unpaginate noerror reader username auth host
These functions are simple wrappers around ghub-request. Their
signature is identical to that of the latter, except that they do
not have an argument named METHOD. The http method is instead given
by the second word in the function name.
As described in the documentation for ghub-request, it depends on
the used method whether the value of the PARAMS argument is used as
the query or the payload. For the "HEAD" and "GET" methods it is
used as the query.
-- Function: ghub-put resource &optional params &key query payload
headers unpaginate noerror reader username auth host
-- Function: ghub-post resource &optional params &key query payload
headers unpaginate noerror reader username auth host
-- Function: ghub-patch resource &optional params &key query payload
headers unpaginate noerror reader username auth host
-- Function: ghub-delete resource &optional params &key query payload
headers unpaginate noerror reader username auth host
These functions are simple wrappers around ghub-request. Their
signature is identical to that of the latter, except that they do
not have an argument named METHOD. The http method is instead given
by the second word in the function name.
As described in the documentation for ghub-request, it depends on
the used method whether the value of the PARAMS argument is used as
the query or the payload. For the "PUT", "POST", "PATCH" and
"DELETE" methods it is used as the payload.
-- Function: ghub-wait resource &optional username auth host duration
Some API requests result in an immediate successful response even
when the requested action has not actually been carried out yet.
An example is the request for the creation of a new repository,
which doesnt cause the repository to immediately become available.
The Github API documentation usually mention this when describing
an affected resource.
If you want to do something with some resource right after creating
after making a request for its creation, then you might have to
wait for it to actually be created. This function can be used to
do so. It repeatedly tries to access the resource until it becomes
available or until the timeout exceeds. In the latter case it
signals ghub-error.
RESOURCE specifies the resource that this function waits for.
DURATION specifies for how many seconds to wait at most, defaulting
to 64 seconds. Emacs will block during that time, but the user can
abort using C-g.
The first attempt is made immediately and often that will actually
succeed. If not, then another attempt is made after two seconds,
and each subsequent attempt is made after waiting as long as we
already waited between all preceding attempts combined.
See ghub-requests documentation above for information about the
other arguments.

File: ghub.info, Node: Authentication, Next: Configuration Variables, Prev: Making Requests, Up: API
6.2 Authentication
==================
-- Command: ghub-create-token
This command creates a new token using the values it reads from the
user and then stores it according to variable auth-sources. It
can also be called non-interactively, but you shouldnt do that
yourself.
This is useful if you want fully setup things before attempting to
make the initial request, if you want to provide fewer than the
requested scopes or customize auth-sources first, or if something
has gone wrong when using the wizard that is used when making a
request without doing this first. (Note that instead of using this
command you can also just repeat the initial request after making
the desired adjustments — that is easier.)
This command reads, in that order, the HOST (Github instance), the
USERNAME, the PACKAGE and the SCOPES in the minibuffer, providing
reasonable default choices. SCOPES defaults to the scopes that
PACKAGE requests using the variable PACKAGE-github-token-scopes.
-- Command: ghub-token-scopes
Users are free to give a token access to fewer scopes than what the
respective package requested. That can of course lead to issues
and package maintainers have to be able to quickly determine if
such a (mis-)configuration is the root cause when users report
issues.
This command reads the required values in the minibuffer and then
shows a message containing these values along with the scopes of
the respective token. It also returns the scopes (only) when
called non-interactively. Also see *note Using Ghub in a
Package::.

File: ghub.info, Node: Configuration Variables, Prev: Authentication, Up: API
6.3 Configuration Variables
===========================
The username and, unless you only use Github.com itself, the Github
Enterprise instance have to be configured using Git variables. In rare
cases it might also be necessary to specify the identity of the local
machine, which is done using a lisp variable.
-- Variable: github.user
The Github.com username. This should be set globally and if you
have multiple Github.com user accounts, then you should set this
locally only for those repositories that you want to access using
the secondary identity.
-- Variable: github.HOST.user
This variable serves the same purpose as github.user but for the
Github Enterprise instance identified by HOST.
The reason why separate variables are used is that this makes it
possible to set the both values globally instead of having to set
one of the values locally in each and every repository that is
connected to the Github Enterprise instance, not Github.com.
-- Variable: github.host
This variable should only be set locally for a repository and
specifies the Github Enterprise edition that that repository is
connected to. You should not set this globally because then each
and every repository becomes connected to the specified Github
Enterprise instance, including those that should actually be
connected to Github.com.
When this is undefined, then "api.github.com" is used (define in
the constant ghub-default-host-host, which you should never
attempt to change.)
-- Variable: ghub-override-system-name
Ghub uses a different token for each quadruple (USERNAME PACKAGE
HOST LOCAL-MACHINE). Theoretically it could reuse tokens to some
extend but that would be more difficult to implement, less
flexible, and less secure (though slightly more convenient).
A token is identified on the respective Github instance (Github.com
or a Github Enterprise instance) using the pair (PACKAGE .
LOCAL-MACHINE), or more precisely the string "Emacs package
PACKAGE @ LOCAL-MACHINE". USERNAME and HOST do not have to be
encoded because the token is stored for USERNAME on HOST and cannot
be used by another user and/or on another instance.
There is one potential problem though; for any given (PACKAGE .
LOCAL-MACHINE) there can only be one token identified by "Emacs
package PACKAGE @ LOCAL-MACHINE", Github does not allow multiple
tokens with the same description because it uses the description as
the identifier. (It could use some hash instead, but alas it does
not.)
If you have multiple machines and some of them have the same name,
then you should probably change that as this is not how thing ought
to be. However if you dual-boot, then it might make sense to give
that machine the same name regardless of what operating system you
have booted into.
You could use the same token on both operating systems, but setting
that up might be somewhat difficult because it is not possible to
download an existing token from Github. You could of course
locally copy the token, but that is inconvenient and would make it
harder to only revoke the token used on your infected Windows
installation without also revoking it for your totally safe *BSD
installation.
Alternatively you can set this variable to a unique value, that
will then be used to identify the local machine instead of the
value returned by system-name.

Tag Table:
Node: Top757
Node: Introduction2781
Node: Limitations5317
Node: Getting Started7458
Node: Setting the Username7960
Node: Interactively Creating and Storing a Token9385
Node: Manually Creating and Storing a Token15340
Node: How Ghub uses Auth-Source16428
Node: Using Ghub in Personal Scripts18071
Node: Using Ghub in a Package19520
Node: API22085
Node: Making Requests22512
Node: Authentication31069
Node: Configuration Variables32868

End Tag Table

Local Variables:
coding: utf-8
End:

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "gist" "gist.el" (23122 58410 136945 52000))
;;;### (autoloads nil "gist" "gist.el" (23124 14357 395457 484000))
;;; Generated autoloads from gist.el
(autoload 'gist-region "gist" "\

View File

@ -1,43 +0,0 @@
;;; git-commit-autoloads.el --- automatically extracted autoloads
;;
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "git-commit" "git-commit.el" (23122 58418 104007
;;;;;; 587000))
;;; Generated autoloads from git-commit.el
(defvar global-git-commit-mode t "\
Non-nil if Global Git-Commit mode is enabled.
See the `global-git-commit-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `global-git-commit-mode'.")
(custom-autoload 'global-git-commit-mode "git-commit" nil)
(autoload 'global-git-commit-mode "git-commit" "\
Edit Git commit messages.
This global mode arranges for `git-commit-setup' to be called
when a Git commit message file is opened. That usually happens
when Git uses the Emacsclient as $GIT_EDITOR to have the user
provide such a commit message.
\(fn &optional ARG)" t nil)
(defconst git-commit-filename-regexp "/\\(\\(\\(COMMIT\\|NOTES\\|PULLREQ\\|TAG\\)_EDIT\\|MERGE_\\|\\)MSG\\|\\(BRANCH\\|EDIT\\)_DESCRIPTION\\)\\'")
(autoload 'git-commit-setup "git-commit" "\
\(fn)" nil nil)
;;;***
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; End:
;;; git-commit-autoloads.el ends here

View File

@ -1,2 +0,0 @@
;;; -*- no-byte-compile: t -*-
(define-package "git-commit" "20180107.1020" "Edit Git commit messages" '((emacs "24.4") (dash "20170810") (with-editor "20170817")) :commit "53eeafcdcb12f9deb74548ffa5b17c397ad7def2" :url "https://github.com/magit/magit" :keywords '("git" "tools" "vc"))

View File

@ -1,833 +0,0 @@
;;; git-commit.el --- Edit Git commit messages -*- lexical-binding: t; -*-
;; Copyright (C) 2010-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Authors: Jonas Bernoulli <jonas@bernoul.li>
;; Sebastian Wiesner <lunaryorn@gmail.com>
;; Florian Ragwitz <rafl@debian.org>
;; Marius Vollmer <marius.vollmer@gmail.com>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Package-Requires: ((emacs "24.4") (dash "20170810") (with-editor "20170817"))
;; Package-Version: 20180107.1020
;; Keywords: git tools vc
;; Homepage: https://github.com/magit/magit
;; This file is not part of GNU Emacs.
;; This file 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 file 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 file. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This package assists the user in writing good Git commit messages.
;; While Git allows for the message to be provided on the command
;; line, it is preferable to tell Git to create the commit without
;; actually passing it a message. Git then invokes the `$GIT_EDITOR'
;; (or if that is undefined `$EDITOR') asking the user to provide the
;; message by editing the file ".git/COMMIT_EDITMSG" (or another file
;; in that directory, e.g. ".git/MERGE_MSG" for merge commits).
;; When `global-git-commit-mode' is enabled, which it is by default,
;; then opening such a file causes the features described below, to
;; be enabled in that buffer. Normally this would be done using a
;; major-mode but to allow the use of any major-mode, as the user sees
;; fit, it is done here by running a setup function, which among other
;; things turns on the preferred major-mode, by default `text-mode'.
;; Git waits for the `$EDITOR' to finish and then either creates the
;; commit using the contents of the file as commit message, or, if the
;; editor process exited with a non-zero exit status, aborts without
;; creating a commit. Unfortunately Emacsclient (which is what Emacs
;; users should be using as `$EDITOR' or at least as `$GIT_EDITOR')
;; does not differentiate between "successfully" editing a file and
;; aborting; not out of the box that is.
;; By making use of the `with-editor' package this package provides
;; both ways of finish an editing session. In either case the file
;; is saved, but Emacseditor's exit code differs.
;;
;; C-c C-c Finish the editing session successfully by returning
;; with exit code 0. Git then creates the commit using
;; the message it finds in the file.
;;
;; C-c C-k Aborts the edit editing session by returning with exit
;; code 1. Git then aborts the commit.
;; Aborting the commit does not cause the message to be lost, but
;; relying solely on the file not being tampered with is risky. This
;; package additionally stores all aborted messages for the duration
;; of the current session (i.e. until you close Emacs). To get back
;; an aborted message use M-p and M-n while editing a message.
;;
;; M-p Replace the buffer contents with the previous message
;; from the message ring. Of course only after storing
;; the current content there too.
;;
;; M-n Replace the buffer contents with the next message from
;; the message ring, after storing the current content.
;; Some support for pseudo headers as used in some projects is
;; provided by these commands:
;;
;; C-c C-s Insert a Signed-off-by header.
;; C-c C-a Insert a Acked-by header.
;; C-c C-m Insert a Modified-by header.
;; C-c C-t Insert a Tested-by header.
;; C-c C-r Insert a Reviewed-by header.
;; C-c C-o Insert a Cc header.
;; C-c C-p Insert a Reported-by header.
;; C-c M-s Insert a Suggested-by header.
;; When Git requests a commit message from the user, it does so by
;; having her edit a file which initially contains some comments,
;; instructing her what to do, and providing useful information, such
;; as which files were modified. These comments, even when left
;; intact by the user, do not become part of the commit message. This
;; package ensures these comments are propertizes as such and further
;; prettifies them by using different faces for various parts, such as
;; files.
;; Finally this package highlights style errors, like lines that are
;; too long, or when the second line is not empty. It may even nag
;; you when you attempt to finish the commit without having fixed
;; these issues. The style checks and many other settings can easily
;; be configured:
;;
;; M-x customize-group RET git-commit RET
;;; Code:
;;;; Dependencies
(require 'dash)
(require 'diff-mode)
(require 'log-edit)
(require 'magit-git nil t)
(require 'magit-utils nil t)
(require 'ring)
(require 'server)
(require 'with-editor)
(eval-when-compile (require 'recentf))
;;;; Declarations
(defvar flyspell-generic-check-word-predicate)
(defvar font-lock-beg)
(defvar font-lock-end)
(declare-function magit-expand-git-file-name 'magit-git)
(declare-function magit-list-local-branch-names 'magit-git)
(declare-function magit-list-remote-branch-names 'magit-git)
;;; Options
;;;; Variables
(defgroup git-commit nil
"Edit Git commit messages."
:prefix "git-commit-"
:link '(info-link "(magit)Editing Commit Messages")
:group 'tools)
;;;###autoload
(define-minor-mode global-git-commit-mode
"Edit Git commit messages.
This global mode arranges for `git-commit-setup' to be called
when a Git commit message file is opened. That usually happens
when Git uses the Emacsclient as $GIT_EDITOR to have the user
provide such a commit message."
:group 'git-commit
:type 'boolean
:global t
:init-value t
:initialize (lambda (symbol exp)
(custom-initialize-default symbol exp)
(when global-git-commit-mode
(add-hook 'find-file-hook 'git-commit-setup-check-buffer)))
(if global-git-commit-mode
(add-hook 'find-file-hook 'git-commit-setup-check-buffer)
(remove-hook 'find-file-hook 'git-commit-setup-check-buffer)))
(defcustom git-commit-major-mode 'text-mode
"Major mode used to edit Git commit messages.
The major mode configured here is turned on by the minor mode
`git-commit-mode'."
:group 'git-commit
:type '(choice (function-item text-mode)
(const :tag "No major mode")))
(defcustom git-commit-setup-hook
'(git-commit-save-message
git-commit-setup-changelog-support
git-commit-turn-on-auto-fill
git-commit-propertize-diff
with-editor-usage-message)
"Hook run at the end of `git-commit-setup'."
:group 'git-commit
:type 'hook
:get (and (featurep 'magit-utils) 'magit-hook-custom-get)
:options '(git-commit-save-message
git-commit-setup-changelog-support
git-commit-turn-on-auto-fill
git-commit-turn-on-flyspell
git-commit-propertize-diff
bug-reference-mode
with-editor-usage-message))
(defcustom git-commit-finish-query-functions
'(git-commit-check-style-conventions)
"List of functions called to query before performing commit.
The commit message buffer is current while the functions are
called. If any of them returns nil, then the commit is not
performed and the buffer is not killed. The user should then
fix the issue and try again.
The functions are called with one argument. If it is non-nil,
then that indicates that the user used a prefix argument to
force finishing the session despite issues. Functions should
usually honor this wish and return non-nil."
:options '(git-commit-check-style-conventions)
:type 'hook
:group 'git-commit)
(defcustom git-commit-style-convention-checks '(non-empty-second-line)
"List of checks performed by `git-commit-check-style-conventions'.
Valid members are `non-empty-second-line' and `overlong-summary-line'.
That function is a member of `git-commit-finish-query-functions'."
:options '(non-empty-second-line overlong-summary-line)
:type '(list :convert-widget custom-hook-convert-widget)
:group 'git-commit)
(defcustom git-commit-summary-max-length 68
"Column beyond which characters in the summary lines are highlighted.
The highlighting indicates that the summary is getting too long
by some standards. It does in no way imply that going over the
limit a few characters or in some cases even many characters is
anything that deserves shaming. It's just a friendly reminder
that if you can make the summary shorter, then you might want
to consider doing so."
:group 'git-commit
:safe 'numberp
:type 'number)
(defcustom git-commit-fill-column nil
"Override `fill-column' in commit message buffers.
If this is non-nil, then it should be an integer. If that is the
case and the buffer-local value of `fill-column' is not already
set by the time `git-commit-turn-on-auto-fill' is called as a
member of `git-commit-setup-hook', then that function sets the
buffer-local value of `fill-column' to the value of this option.
This option exists mostly for historic reasons. If you are not
already using it, then you probably shouldn't start doing so."
:group 'git-commit
:safe 'numberp
:type '(choice (const :tag "use regular fill-column")
number))
(make-obsolete-variable 'git-commit-fill-column 'fill-column
"Magit 2.11.0" 'set)
(defcustom git-commit-known-pseudo-headers
'("Signed-off-by" "Acked-by" "Modified-by" "Cc"
"Suggested-by" "Reported-by" "Tested-by" "Reviewed-by")
"A list of Git pseudo headers to be highlighted."
:group 'git-commit
:safe (lambda (val) (and (listp val) (-all-p 'stringp val)))
:type '(repeat string))
;;;; Faces
(defgroup git-commit-faces nil
"Faces used for highlighting Git commit messages."
:prefix "git-commit-"
:group 'git-commit
:group 'faces)
(defface git-commit-summary
'((t :inherit font-lock-type-face))
"Face used for the summary in commit messages."
:group 'git-commit-faces)
(defface git-commit-overlong-summary
'((t :inherit font-lock-warning-face))
"Face used for the tail of overlong commit message summaries."
:group 'git-commit-faces)
(defface git-commit-nonempty-second-line
'((t :inherit font-lock-warning-face))
"Face used for non-whitespace on the second line of commit messages."
:group 'git-commit-faces)
(defface git-commit-note
'((t :inherit font-lock-string-face))
"Face used for notes in commit messages."
:group 'git-commit-faces)
(defface git-commit-pseudo-header
'((t :inherit font-lock-string-face))
"Face used for pseudo headers in commit messages."
:group 'git-commit-faces)
(defface git-commit-known-pseudo-header
'((t :inherit font-lock-keyword-face))
"Face used for the keywords of known pseudo headers in commit messages."
:group 'git-commit-faces)
(defface git-commit-comment-branch-local
(if (featurep 'magit)
'((t :inherit magit-branch-local))
'((t :inherit font-lock-variable-name-face)))
"Face used for names of local branches in commit message comments."
:group 'git-commit-faces)
(define-obsolete-face-alias 'git-commit-comment-branch
'git-commit-comment-branch-local "Git-Commit 2.12.0")
(defface git-commit-comment-branch-remote
(if (featurep 'magit)
'((t :inherit magit-branch-remote))
'((t :inherit font-lock-variable-name-face)))
"Face used for names of remote branches in commit message comments.
This is only used if Magit is available."
:group 'git-commit-faces)
(defface git-commit-comment-detached
'((t :inherit git-commit-comment-branch-local))
"Face used for detached `HEAD' in commit message comments."
:group 'git-commit-faces)
(defface git-commit-comment-heading
'((t :inherit git-commit-known-pseudo-header))
"Face used for headings in commit message comments."
:group 'git-commit-faces)
(defface git-commit-comment-file
'((t :inherit git-commit-pseudo-header))
"Face used for file names in commit message comments."
:group 'git-commit-faces)
(defface git-commit-comment-action
'((t :inherit bold))
"Face used for actions in commit message comments."
:group 'git-commit-faces)
;;; Keymap
(defvar git-commit-mode-map
(let ((map (make-sparse-keymap)))
(cond ((featurep 'jkl)
(define-key map (kbd "C-M-i") 'git-commit-prev-message)
(define-key map (kbd "C-M-k") 'git-commit-next-message))
(t
(define-key map (kbd "M-p") 'git-commit-prev-message)
(define-key map (kbd "M-n") 'git-commit-next-message)
;; Old bindings to avoid confusion
(define-key map (kbd "C-c C-x a") 'git-commit-ack)
(define-key map (kbd "C-c C-x i") 'git-commit-suggested)
(define-key map (kbd "C-c C-x m") 'git-commit-modified)
(define-key map (kbd "C-c C-x o") 'git-commit-cc)
(define-key map (kbd "C-c C-x p") 'git-commit-reported)
(define-key map (kbd "C-c C-x r") 'git-commit-review)
(define-key map (kbd "C-c C-x s") 'git-commit-signoff)
(define-key map (kbd "C-c C-x t") 'git-commit-test)))
(define-key map (kbd "C-c C-a") 'git-commit-ack)
(define-key map (kbd "C-c C-i") 'git-commit-suggested)
(define-key map (kbd "C-c C-m") 'git-commit-modified)
(define-key map (kbd "C-c C-o") 'git-commit-cc)
(define-key map (kbd "C-c C-p") 'git-commit-reported)
(define-key map (kbd "C-c C-r") 'git-commit-review)
(define-key map (kbd "C-c C-s") 'git-commit-signoff)
(define-key map (kbd "C-c C-t") 'git-commit-test)
(define-key map (kbd "C-c M-s") 'git-commit-save-message)
map)
"Key map used by `git-commit-mode'.")
;;; Menu
(require 'easymenu)
(easy-menu-define git-commit-mode-menu git-commit-mode-map
"Git Commit Mode Menu"
'("Commit"
["Previous" git-commit-prev-message t]
["Next" git-commit-next-message t]
"-"
["Ack" git-commit-ack :active t
:help "Insert an 'Acked-by' header"]
["Sign-Off" git-commit-signoff :active t
:help "Insert a 'Signed-off-by' header"]
["Modified-by" git-commit-modified :active t
:help "Insert a 'Modified-by' header"]
["Tested-by" git-commit-test :active t
:help "Insert a 'Tested-by' header"]
["Reviewed-by" git-commit-review :active t
:help "Insert a 'Reviewed-by' header"]
["CC" git-commit-cc t
:help "Insert a 'Cc' header"]
["Reported" git-commit-reported :active t
:help "Insert a 'Reported-by' header"]
["Suggested" git-commit-suggested t
:help "Insert a 'Suggested-by' header"]
"-"
["Save" git-commit-save-message t]
["Cancel" with-editor-cancel t]
["Commit" with-editor-finish t]))
;;; Hooks
;;;###autoload
(defconst git-commit-filename-regexp "/\\(\
\\(\\(COMMIT\\|NOTES\\|PULLREQ\\|TAG\\)_EDIT\\|MERGE_\\|\\)MSG\
\\|\\(BRANCH\\|EDIT\\)_DESCRIPTION\\)\\'")
(eval-after-load 'recentf
'(add-to-list 'recentf-exclude git-commit-filename-regexp))
(add-to-list 'with-editor-file-name-history-exclude git-commit-filename-regexp)
(defun git-commit-setup-font-lock-in-buffer ()
(and buffer-file-name
(string-match-p git-commit-filename-regexp buffer-file-name)
(git-commit-setup-font-lock)))
(add-hook 'after-change-major-mode-hook 'git-commit-setup-font-lock-in-buffer)
(defun git-commit-setup-check-buffer ()
(and buffer-file-name
(string-match-p git-commit-filename-regexp buffer-file-name)
(git-commit-setup)))
(defvar git-commit-mode)
;;;###autoload
(defun git-commit-setup ()
;; cygwin git will pass a cygwin path (/cygdrive/c/foo/.git/...),
;; try to handle this in window-nt Emacs.
(--when-let
(and (eq system-type 'windows-nt)
(not (file-accessible-directory-p default-directory))
(if (require 'magit-git nil t)
;; Emacs prepends a "c:".
(magit-expand-git-file-name (substring buffer-file-name 2))
;; Fallback if we can't load `magit-git'.
(and (string-match "\\`[a-z]:/\\(cygdrive/\\)?\\([a-z]\\)/\\(.*\\)"
buffer-file-name)
(concat (match-string 2 buffer-file-name) ":/"
(match-string 3 buffer-file-name)))))
(when (file-accessible-directory-p (file-name-directory it))
(find-alternate-file it)))
(when git-commit-major-mode
(let ((auto-mode-alist (list (cons (concat "\\`"
(regexp-quote buffer-file-name)
"\\'")
git-commit-major-mode)))
;; The major-mode hook might want to consult these minor
;; modes, while the minor-mode hooks might want to consider
;; the major mode.
(git-commit-mode t)
(with-editor-mode t))
(normal-mode t)))
(setq with-editor-show-usage nil)
(unless with-editor-mode
;; Maybe already enabled when using `shell-command' or an Emacs shell.
(with-editor-mode 1))
(add-hook 'with-editor-finish-query-functions
'git-commit-finish-query-functions nil t)
(add-hook 'with-editor-pre-finish-hook
'git-commit-save-message nil t)
(add-hook 'with-editor-pre-cancel-hook
'git-commit-save-message nil t)
(setq with-editor-cancel-message
'git-commit-cancel-message)
(make-local-variable 'log-edit-comment-ring-index)
(git-commit-mode 1)
(git-commit-setup-font-lock)
(when (boundp 'save-place)
(setq save-place nil))
(save-excursion
(goto-char (point-min))
(when (looking-at "\\`\\(\\'\\|\n[^\n]\\)")
(open-line 1)))
(run-hooks 'git-commit-setup-hook)
(set-buffer-modified-p nil))
(define-minor-mode git-commit-mode
"Auxiliary minor mode used when editing Git commit messages.
This mode is only responsible for setting up some key bindings.
Don't use it directly, instead enable `global-git-commit-mode'."
:lighter "")
(put 'git-commit-mode 'permanent-local t)
(defun git-commit-setup-changelog-support ()
"Treat ChangeLog entries as paragraphs."
(setq-local paragraph-start (concat paragraph-start "\\|\\*\\|(")))
(defun git-commit-turn-on-auto-fill ()
"Unconditionally turn on Auto Fill mode.
If `git-commit-fill-column' is non-nil, and `fill-column'
doesn't already have a buffer-local value, then set that
to `git-commit-fill-column'."
(when (and (numberp git-commit-fill-column)
(not (local-variable-p 'fill-column)))
(setq fill-column git-commit-fill-column))
(setq-local comment-auto-fill-only-comments nil)
(turn-on-auto-fill))
(defun git-commit-turn-on-flyspell ()
"Unconditionally turn on Flyspell mode.
Also prevent comments from being checked and
finally check current non-comment text."
(require 'flyspell)
(turn-on-flyspell)
(setq flyspell-generic-check-word-predicate
'git-commit-flyspell-verify)
(let (end)
(save-excursion
(goto-char (point-max))
(while (and (not (bobp)) (looking-at "^\\(#\\|$\\)"))
(forward-line -1))
(unless (looking-at "^\\(#\\|$\\)")
(forward-line))
(setq end (point)))
(flyspell-region (point-min) end)))
(defun git-commit-flyspell-verify ()
(not (= (char-after (line-beginning-position)) ?#)))
(defun git-commit-finish-query-functions (force)
(run-hook-with-args-until-failure
'git-commit-finish-query-functions force))
(defun git-commit-check-style-conventions (force)
"Check for violations of certain basic style conventions.
For each violation ask the user if she wants to proceed anyway.
Option `git-commit-check-style-conventions' controls which
conventions are checked."
(or force
(save-excursion
(goto-char (point-min))
(re-search-forward (git-commit-summary-regexp) nil t)
(if (equal (match-string 1) "")
t ; Just try; we don't know whether --allow-empty-message was used.
(and (or (not (memq 'overlong-summary-line
git-commit-style-convention-checks))
(equal (match-string 2) "")
(y-or-n-p "Summary line is too long. Commit anyway? "))
(or (not (memq 'non-empty-second-line
git-commit-style-convention-checks))
(not (match-string 3))
(y-or-n-p "Second line is not empty. Commit anyway? ")))))))
(defun git-commit-cancel-message ()
(message
(concat "Commit canceled"
(and (memq 'git-commit-save-message with-editor-pre-cancel-hook)
". Message saved to `log-edit-comment-ring'"))))
;;; History
(defun git-commit-prev-message (arg)
"Cycle backward through message history, after saving current message.
With a numeric prefix ARG, go back ARG comments."
(interactive "*p")
(when (and (git-commit-save-message) (> arg 0))
(setq log-edit-comment-ring-index
(log-edit-new-comment-index
arg (ring-length log-edit-comment-ring))))
(save-restriction
(goto-char (point-min))
(narrow-to-region (point)
(if (re-search-forward (concat "^" comment-start))
(max 1 (- (point) 2))
(point-max)))
(log-edit-previous-comment arg)))
(defun git-commit-next-message (arg)
"Cycle forward through message history, after saving current message.
With a numeric prefix ARG, go forward ARG comments."
(interactive "*p")
(git-commit-prev-message (- arg)))
(defun git-commit-save-message ()
"Save current message to `log-edit-comment-ring'."
(interactive)
(--when-let (git-commit-buffer-message)
(unless (ring-member log-edit-comment-ring it)
(ring-insert log-edit-comment-ring it))))
(defun git-commit-buffer-message ()
(let ((flush (concat "^" comment-start))
(str (buffer-substring-no-properties (point-min) (point-max))))
(with-temp-buffer
(insert str)
(goto-char (point-min))
(when (re-search-forward (concat flush " -+ >8 -+$") nil t)
(delete-region (point-at-bol) (point-max)))
(goto-char (point-min))
(flush-lines flush)
(goto-char (point-max))
(unless (eq (char-before) ?\n)
(insert ?\n))
(setq str (buffer-string)))
(unless (string-match "\\`[ \t\n\r]*\\'" str)
(when (string-match "\\`\n\\{2,\\}" str)
(setq str (replace-match "\n" t t str)))
(when (string-match "\n\\{2,\\}\\'" str)
(setq str (replace-match "\n" t t str)))
str)))
;;; Headers
(defun git-commit-ack (name mail)
"Insert a header acknowledging that you have looked at the commit."
(interactive (git-commit-self-ident))
(git-commit-insert-header "Acked-by" name mail))
(defun git-commit-modified (name mail)
"Insert a header to signal that you have modified the commit."
(interactive (git-commit-self-ident))
(git-commit-insert-header "Modified-by" name mail))
(defun git-commit-review (name mail)
"Insert a header acknowledging that you have reviewed the commit."
(interactive (git-commit-self-ident))
(git-commit-insert-header "Reviewed-by" name mail))
(defun git-commit-signoff (name mail)
"Insert a header to sign off the commit."
(interactive (git-commit-self-ident))
(git-commit-insert-header "Signed-off-by" name mail))
(defun git-commit-test (name mail)
"Insert a header acknowledging that you have tested the commit."
(interactive (git-commit-self-ident))
(git-commit-insert-header "Tested-by" name mail))
(defun git-commit-cc (name mail)
"Insert a header mentioning someone who might be interested."
(interactive (git-commit-read-ident))
(git-commit-insert-header "Cc" name mail))
(defun git-commit-reported (name mail)
"Insert a header mentioning the person who reported the issue."
(interactive (git-commit-read-ident))
(git-commit-insert-header "Reported-by" name mail))
(defun git-commit-suggested (name mail)
"Insert a header mentioning the person who suggested the change."
(interactive (git-commit-read-ident))
(git-commit-insert-header "Suggested-by" name mail))
(defun git-commit-self-ident ()
(list (or (getenv "GIT_AUTHOR_NAME")
(getenv "GIT_COMMITTER_NAME")
(ignore-errors (car (process-lines "git" "config" "user.name")))
user-full-name
(read-string "Name: "))
(or (getenv "GIT_AUTHOR_EMAIL")
(getenv "GIT_COMMITTER_EMAIL")
(getenv "EMAIL")
(ignore-errors (car (process-lines "git" "config" "user.email")))
(read-string "Email: "))))
(defun git-commit-read-ident ()
(list (read-string "Name: ")
(read-string "Email: ")))
(defun git-commit-insert-header (header name email)
(setq header (format "%s: %s <%s>" header name email))
(save-excursion
(goto-char (point-max))
(cond ((re-search-backward "^[-a-zA-Z]+: [^<]+? <[^>]+>" nil t)
(end-of-line)
(insert ?\n header)
(unless (= (char-after) ?\n)
(insert ?\n)))
(t
(while (re-search-backward (concat "^" comment-start) nil t))
(unless (looking-back "\n\n" nil)
(insert ?\n))
(insert header ?\n)))
(unless (or (eobp) (= (char-after) ?\n))
(insert ?\n))))
;;; Font-Lock
(defun git-commit-summary-regexp ()
(concat
;; Leading empty lines and comments
(format "\\`\\(?:^\\(?:\\s-*\\|%s.*\\)\n\\)*" comment-start)
;; Summary line
(format "\\(.\\{0,%d\\}\\)\\(.*\\)" git-commit-summary-max-length)
;; Non-empty non-comment second line
(format "\\(?:\n%s\\|\n\\(.+\\)\\)?" comment-start)))
(defun git-commit-extend-region-summary-line ()
"Identify the multiline summary-regexp construct.
Added to `font-lock-extend-region-functions'."
(save-excursion
(save-match-data
(goto-char (point-min))
(when (looking-at (git-commit-summary-regexp))
(let ((summary-beg (match-beginning 0))
(summary-end (match-end 0)))
(when (or (< summary-beg font-lock-beg summary-end)
(< summary-beg font-lock-end summary-end))
(setq font-lock-beg (min font-lock-beg summary-beg))
(setq font-lock-end (max font-lock-end summary-end))))))))
(defvar-local git-commit--branch-name-regexp nil)
(defconst git-commit-comment-headings
'("Changes to be committed:"
"Untracked files:"
"Changed but not updated:"
"Changes not staged for commit:"
"Unmerged paths:"
"Author:"
"Date:"))
(defconst git-commit-font-lock-keywords-1
'(;; Pseudo headers
(eval . `(,(format "^\\(%s:\\)\\( .*\\)"
(regexp-opt git-commit-known-pseudo-headers))
(1 'git-commit-known-pseudo-header)
(2 'git-commit-pseudo-header)))
("^[-a-zA-Z]+: [^<]+? <[^>]+>"
(0 'git-commit-pseudo-header))
;; Summary
(eval . `(,(git-commit-summary-regexp)
(1 'git-commit-summary t)))
;; - Note (overrides summary)
("\\[.+?\\]"
(0 'git-commit-note t))
;; - Non-empty second line (overrides summary and note)
(eval . `(,(git-commit-summary-regexp)
(2 'git-commit-overlong-summary t t)
(3 'git-commit-nonempty-second-line t t)))))
(defconst git-commit-font-lock-keywords-2
`(,@git-commit-font-lock-keywords-1
;; Comments
(eval . `(,(format "^%s.*" comment-start)
(0 'font-lock-comment-face)))
(eval . `(,(format "^%s On branch \\(.*\\)" comment-start)
(1 'git-commit-comment-branch-local t)))
(eval . `(,(format "^%s \\(HEAD\\) detached at" comment-start)
(1 'git-commit-comment-detached t)))
(eval . `(,(format "^%s %s" comment-start
(regexp-opt git-commit-comment-headings t))
(1 'git-commit-comment-heading t)))
(eval . `(,(format "^%s\t\\(?:\\([^:\n]+\\):\\s-+\\)?\\(.*\\)" comment-start)
(1 'git-commit-comment-action t t)
(2 'git-commit-comment-file t)))))
(defconst git-commit-font-lock-keywords-3
`(,@git-commit-font-lock-keywords-2
;; More comments
(eval
;; Your branch is ahead of 'master' by 3 commits.
;; Your branch is behind 'master' by 2 commits, and can be fast-forwarded.
. `(,(format
"^%s Your branch is \\(?:ahead\\|behind\\) of '%s' by \\([0-9]*\\)"
comment-start git-commit--branch-name-regexp)
(1 'git-commit-comment-branch-local t)
(2 'git-commit-comment-branch-remote t)
(3 'bold t)))
(eval
;; Your branch is up to date with 'master'.
;; Your branch and 'master' have diverged,
. `(,(format
"^%s Your branch \\(?:is up-to-date with\\|and\\) '%s'"
comment-start git-commit--branch-name-regexp)
(1 'git-commit-comment-branch-local t)
(2 'git-commit-comment-branch-remote t)))
(eval
;; and have 1 and 2 different commits each, respectively.
. `(,(format
"^%s and have \\([0-9]*\\) and \\([0-9]*\\) commits each"
comment-start)
(1 'bold t)
(2 'bold t)))))
(defvar git-commit-font-lock-keywords git-commit-font-lock-keywords-2
"Font-Lock keywords for Git-Commit mode.")
(defun git-commit-setup-font-lock ()
(let ((table (make-syntax-table (syntax-table))))
(when comment-start
(modify-syntax-entry (string-to-char comment-start) "." table))
(modify-syntax-entry ?# "." table)
(modify-syntax-entry ?\" "." table)
(modify-syntax-entry ?\' "." table)
(modify-syntax-entry ?` "." table)
(set-syntax-table table))
(setq-local comment-start
(or (ignore-errors
(car (process-lines "git" "config" "core.commentchar")))
"#"))
(setq-local comment-start-skip (format "^%s+[\s\t]*" comment-start))
(setq-local comment-end-skip "\n")
(setq-local comment-use-syntax nil)
(setq-local git-commit--branch-name-regexp
(if (featurep 'magit-git)
;; Font-Lock wants every submatch to succeed.
(format "\\(%s\\|\\)\\(%s\\|\\)"
(regexp-opt (magit-list-local-branch-names))
(regexp-opt (magit-list-remote-branch-names)))
"\\([^']*\\)"))
(setq-local font-lock-multiline t)
(add-hook 'font-lock-extend-region-functions
#'git-commit-extend-region-summary-line
t t)
(font-lock-add-keywords nil git-commit-font-lock-keywords t))
(defun git-commit-propertize-diff ()
(save-excursion
(goto-char (point-min))
(when (re-search-forward "^diff --git" nil t)
(beginning-of-line)
(let ((buffer (current-buffer)))
(insert
(with-temp-buffer
(insert
(with-current-buffer buffer
(prog1 (buffer-substring-no-properties (point) (point-max))
(delete-region (point) (point-max)))))
(let ((diff-default-read-only nil))
(diff-mode))
(let (font-lock-verbose font-lock-support-mode)
(if (fboundp 'font-lock-ensure)
(font-lock-ensure)
(with-no-warnings
(font-lock-fontify-buffer))))
(let (next (pos (point-min)))
(while (setq next (next-single-property-change pos 'face))
(put-text-property pos next 'font-lock-face
(get-text-property pos 'face))
(setq pos next))
(put-text-property pos (point-max) 'font-lock-face
(get-text-property pos 'face)))
(buffer-string)))))))
(provide 'git-commit)
;;; git-commit.el ends here

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "git-timemachine" "git-timemachine.el" (23122
;;;;;; 58410 633862 392000))
;;;### (autoloads nil "git-timemachine" "git-timemachine.el" (23124
;;;;;; 14357 825459 511000))
;;; Generated autoloads from git-timemachine.el
(autoload 'git-timemachine-toggle "git-timemachine" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "gitconfig-mode" "gitconfig-mode.el" (23122
;;;;;; 58411 44069 324000))
;;;### (autoloads nil "gitconfig-mode" "gitconfig-mode.el" (23124
;;;;;; 14358 205461 302000))
;;; Generated autoloads from gitconfig-mode.el
(autoload 'gitconfig-mode "gitconfig-mode" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "gitignore-mode" "gitignore-mode.el" (23122
;;;;;; 58411 430931 146000))
;;;### (autoloads nil "gitignore-mode" "gitignore-mode.el" (23124
;;;;;; 14358 595463 140000))
;;; Generated autoloads from gitignore-mode.el
(autoload 'gitignore-mode "gitignore-mode" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "god-mode" "god-mode.el" (23122 58411 804452
;;;;;; 905000))
;;;### (autoloads nil "god-mode" "god-mode.el" (23124 14359 2131
;;;;;; 723000))
;;; Generated autoloads from god-mode.el
(autoload 'god-local-mode "god-mode" "\
@ -30,7 +30,7 @@ Activate God mode locally on individual buffers when appropriate.
;;;***
;;;### (autoloads nil nil ("god-mode-isearch.el" "god-mode-pkg.el")
;;;;;; (23122 58411 821127 984000))
;;;;;; (23124 14359 25465 166000))
;;;***

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "grizzl" "grizzl.el" (23122 58412 308037 326000))
;;;### (autoloads nil "grizzl" "grizzl.el" (23124 14359 418800 353000))
;;; Generated autoloads from grizzl.el
(autoload 'grizzl-make-index "grizzl" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "guru-mode" "guru-mode.el" (23122 58412 744920
;;;;;; 55000))
;;;### (autoloads nil "guru-mode" "guru-mode.el" (23124 14359 795468
;;;;;; 795000))
;;; Generated autoloads from guru-mode.el
(autoload 'guru-mode "guru-mode" "\

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil nil ("ht.el") (23122 58405 427902 874000))
;;;### (autoloads nil nil ("ht.el") (23124 14353 762107 28000))
;;;***

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "imenu-anywhere" "imenu-anywhere.el" (23122
;;;;;; 58413 135111 50000))
;;;### (autoloads nil "imenu-anywhere" "imenu-anywhere.el" (23124
;;;;;; 14360 228804 170000))
;;; Generated autoloads from imenu-anywhere.el
(autoload 'imenu-anywhere "imenu-anywhere" "\

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "ivy" "ivy.el" (23122 58431 505213 767000))
;;;### (autoloads nil "ivy" "ivy.el" (23124 14376 352214 61000))
;;; Generated autoloads from ivy.el
(autoload 'ivy-resume "ivy" "\
@ -123,7 +123,7 @@ Switch to another buffer in another window.
;;;***
;;;### (autoloads nil nil ("colir.el" "ivy-overlay.el" "ivy-pkg.el")
;;;;;; (23122 58431 478539 823000))
;;;;;; (23124 14376 322213 917000))
;;;***

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "js2-imenu-extras" "js2-imenu-extras.el" (23122
;;;;;; 58439 550488 409000))
;;;### (autoloads nil "js2-imenu-extras" "js2-imenu-extras.el" (23124
;;;;;; 14383 565582 39000))
;;; Generated autoloads from js2-imenu-extras.el
(autoload 'js2-imenu-extras-setup "js2-imenu-extras" "\
@ -19,8 +19,8 @@ Toggle Imenu support for frameworks and structural patterns.
;;;***
;;;### (autoloads nil "js2-mode" "js2-mode.el" (23122 58439 577160
;;;;;; 729000))
;;;### (autoloads nil "js2-mode" "js2-mode.el" (23124 14383 592248
;;;;;; 834000))
;;; Generated autoloads from js2-mode.el
(autoload 'js2-highlight-unused-variables-mode "js2-mode" "\
@ -56,7 +56,7 @@ variables (`sgml-basic-offset' et al) locally, like so:
;;;***
;;;### (autoloads nil nil ("js2-mode-pkg.el" "js2-old-indent.el")
;;;;;; (23122 58439 567158 609000))
;;;;;; (23124 14383 582248 786000))
;;;***

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "json-mode" "json-mode.el" (23122 58446 548492
;;;;;; 43000))
;;;### (autoloads nil "json-mode" "json-mode.el" (23124 14387 428933
;;;;;; 928000))
;;; Generated autoloads from json-mode.el
(defconst json-mode-standard-file-ext '(".json" ".jsonld") "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "json-reformat" "json-reformat.el" (23122 58445
;;;;;; 848371 19000))
;;;### (autoloads nil "json-reformat" "json-reformat.el" (23124 14387
;;;;;; 15598 609000))
;;; Generated autoloads from json-reformat.el
(autoload 'json-reformat-region "json-reformat" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "json-snatcher" "json-snatcher.el" (23122 58445
;;;;;; 428296 741000))
;;;### (autoloads nil "json-snatcher" "json-snatcher.el" (23124 14386
;;;;;; 595596 592000))
;;; Generated autoloads from json-snatcher.el
(autoload 'jsons-print-path "json-snatcher" "\

View File

@ -3,8 +3,8 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "let-alist" "let-alist.el" (23122 58417 553777
;;;;;; 68000))
;;;### (autoloads nil "let-alist" "let-alist.el" (23124 14364 108822
;;;;;; 456000))
;;; Generated autoloads from let-alist.el
(autoload 'let-alist "let-alist" "\

View File

@ -3,7 +3,7 @@
;;; Code:
(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil nil ("logito.el") (23122 58406 325022 99000))
;;;### (autoloads nil nil ("logito.el") (23124 14354 768778 439000))
;;;***

View File

@ -1,287 +0,0 @@
Authors
=======
The following people have contributed to Magit, including the
libraries `git-commit.el`, `magit-popup.el`, and `with-editor.el`
which are distributed as separate Elpa packages.
For statistics see https://magit.vc/stats/authors.html.
Names below are sorted alphabetically.
Author
------
- Marius Vollmer <marius.vollmer@gmail.com>
Maintainer
----------
- Jonas Bernoulli <jonas@bernoul.li>
Developers
----------
- Kyle Meyer <kyle@kyleam.com>
- Noam Postavsky <npostavs@users.sourceforge.net>
Retired Maintainers and Developers
----------------------------------
- Nicolas Dudebout <nicolas.dudebout@gatech.edu>
- Peter J. Weisberg <pj@irregularexpressions.net>
- Pieter Praet <pieter@praet.org>
- Phil Jackson <phil@shellarchive.co.uk>
- Rémi Vanicat <vanicat@debian.org>
- Yann Hodique <yann.hodique@gmail.com>
Contributors
------------
- Aaron Culich <aculich@gmail.com>
- Abdo Roig-Maranges <abdo.roig@gmail.com>
- Adam Benanti <0entropy@protonmail.com>
- Adam Porter <adam@alphapapa.net>
- Adam Spiers <emacs@adamspiers.org>
- Adeodato Simó <dato@net.com.org.es>
- Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- Alan Falloon <alan.falloon@gmail.com>
- Aleksey Uimanov <s9gf4ult@gmail.com>
- Alexander Gramiak <fice-t@protonmail.com>
- Alex Dunn <adunn@ucsb.edu>
- Alexey Voinov <alexey.v.voinov@gmail.com>
- Alex Kost <alezost@gmail.com>
- Alex Ott <alexott@gmail.com>
- Allen <darkfeline@felesatra.moe>
- Allen Li <darkfeline@felesatra.moe>
- Andreas Fuchs <asf@boinkor.net>
- Andreas Liljeqvist <andreas.liljeqvist@robacks.se>
- Andreas Rottmann <a.rottmann@gmx.at>
- Andrei Chițu <andrei.chitu1@gmail.com>
- Andrew Kirkpatrick <andrew.kirkpatrick@adelaide.edu.au>
- Andrew Schwartzmeyer <andrew@schwartzmeyer.com>
- Andrey Smirnov <andrew.smirnov@gmail.com>
- Andriy Kmit' <dev@madand.net>
- Andy Sawyer <git@pureabstract.org>
- Barak A. Pearlmutter <barak+git@pearlmutter.net>
- Bar Magal <bmagamb@gmail.com>
- Bart Bakker <bart@thesoftwarecraft.com>
- Basil L. Contovounesios <contovob@tcd.ie>
- Bastian Beischer <beischer@physik.rwth-aachen.de>
- Ben North <ben@redfrontdoor.org>
- Ben Walton <bwalton@artsci.utoronto.ca>
- Bradley Wright <brad@intranation.com>
- Brandon W Maister <quodlibetor@gmail.com>
- Brian Warner <warner@lothar.com>
- Bryan Shell <bryan.shell@orbitz.com>
- Carl Lieberman <liebermancarl@gmail.com>
- Chillar Anand <anand21nanda@gmail.com>
- Chris Bernard <cebernard@gmail.com>
- Chris Done <chrisdone@gmail.com>
- Chris Moore <dooglus@gmail.com>
- Chris Ring <chris@ringthis.com>
- Chris Shoemaker <chris@mojotech.com>
- Christian Dietrich <christian.dietrich@informatik.uni-erlangen.de>
- Christian Kluge <ckfrakturfreak@web.de>
- Christopher Monsanto <chris@monsan.to>
- Cornelius Mika <cornelius.mika@gmail.com>
- Craig Andera <candera@wangdera.com>
- Dale Hagglund <dale.hagglund@gmail.com>
- Damien Cassou <damien@cassou.me>
- Dan Erikson <derikson3@gmail.com>
- Daniel Brockman <daniel@gointeractive.se>
- Daniel Farina <drfarina@acm.org>
- Daniel Hackney <dan@haxney.org>
- Daniel Mai <daniel@danielmai.net>
- Dan LaManna <dan.lamanna@gmail.com>
- Dato Simó <dato@net.com.org.es>
- David Abrahams <dave@boostpro.com>
- David Ellison <davide@voicebox.com>
- David Hull <david.hull@openx.com>
- David L. Rager <ragerdl@gmail.com>
- David Wallin <david.wallin@gmail.com>
- Dennis Paskorz <dennis@walltowall.com>
- Divye Kapoor <divye@google.com>
- Dominique Quatravaux <domq@google.com>
- Duianto Vebotci <vebotci@openmailbox.org>
- Eli Barzilay <eli@barzilay.org>
- Eric Davis <ed@npri.org>
- Eric Schulte <schulte.eric@gmail.com>
- Erik Anderson <erikbpanderson@gmail.com>
- Evgkeni Sampelnikof <esabof@gmail.com>
- Eyal Lotem <eyal.lotem@gmail.com>
- Fabian Wiget <fabacino@gmail.com>
- Felix Geller <fgeller@gmail.com>
- Feng Li <fengli@blackmagicdesign.com>
- Florian Ragwitz <rafl@debian.org>
- Fritz Grabo <fritz.grabo@gmail.com>
- Geoff Shannon <geoffpshannon@gmail.com>
- George Kadianakis <desnacked@gmail.com>
- Graham Clark <grclark@gmail.com>
- Graham Dobbins <gdobbins@protonmail.com>
- Greg A. Woods <woods@planix.com>
- Greg Lucas <greg@glucas.net>
- Greg Sexton <gregsexton@gmail.com>
- Guillaume Martres <smarter@ubuntu.com>
- Hannu Koivisto <azure@iki.fi>
- Hans-Peter Deifel <hpdeifel@gmx.de>
- Ian Eure <ian.eure@gmail.com>
- Ingo Lohmar <i.lohmar@gmail.com>
- Ioan-Adrian Ratiu <adi@adirat.com>
- Ivan Brennan <ivan.brennan@gmail.com>
- Jan Tatarik <jan.tatarik@xing.com>
- Jasper St. Pierre <jstpierre@mecheye.net>
- Jeff Bellegarde <jbellegarde@whitepages.com>
- Jeff Dairiki <dairiki@dairiki.org>
- Jeremy Meng <yumeng@microsoft.com>
- Jesse Alama <jesse.alama@gmail.com>
- Jim Blandy <jimb@red-bean.com>
- Joakim Jalap <JOJA@stoneridge.com>
- Johann Klähn <kljohann@gmail.com>
- John Mastro <john.b.mastro@gmail.com>
- John Wiegley <johnw@newartisans.com>
- Jonas Bernoulli <jonas@bernoul.li>
- Jonathan Roes <jroes@jroes.net>
- Jordan Greenberg <jordan@softwareslave.com>
- Josiah Schwab <jschwab@gmail.com>
- Julien Danjou <julien@danjou.info>
- Justin Burkett <justin@burkett.cc>
- Justin Caratzas <justin.caratzas@gmail.com>
- Justin Guenther <jguenther@gmail.com>
- Justin Thomas <justin.thomas1@gmail.com>
- Kan-Ru Chen <kanru@kanru.info>
- Keshav Kini <keshav.kini@gmail.com>
- Kévin Le Gouguec <kevin.legouguec@gmail.com>
- Kimberly Wolk <kimwolk@hotmail.com>
- Kyle Meyer <kyle@kyleam.com>
- Laurent Laffont <laurent.laffont@gmail.com>
- Laverne Schrock <laverne@schrock.email>
- Leandro Facchinetti <me@leafac.com>
- Lele Gaifax <lele@metapensiero.it>
- Leo Liu <sdl.web@gmail.com>
- Leonardo Etcheverry <leo@kalio.net>
- Lingchao Xin <douglarek@users.noreply.github.com>
- Lluís Vilanova <vilanova@ac.upc.edu>
- Loic Dachary <loic@dachary.org>
- Luís Oliveira <luismbo@gmail.com>
- Luke Amdor <luke.amdor@gmail.com>
- Manuel Vázquez Acosta <mva.led@gmail.com>
- Marcel Wolf <mwolf@ml1.net>
- Marc Herbert <marc.herbert@gmail.com>
- Marcin Bachry <hegel666@gmail.com>
- Marco Craveiro <marco.craveiro@gmail.com>
- Marco Wahl <marcowahlsoft@gmail.com>
- Marc Sherry <msherry@gmail.com>
- Marian Schubert <marian.schubert@gmail.com>
- Mario Rodas <marsam@users.noreply.github.com>
- Marius Vollmer <marius.vollmer@gmail.com>
- Mark Hepburn <Mark.Hepburn@csiro.au>
- Mark Karpov <markkarpov@opmbx.org>
- Mark Oteiza <mvoteiza@udel.edu>
- Matthew Fluet <matthew.fluet@gmail.com>
- Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
- Matus Goljer <dota.keys@gmail.com>
- Michael Fogleman <michaelwfogleman@gmail.com>
- Michael Griffiths <mikey@cich.li>
- Michael Heerdegen <michael_heerdegen@web.de>
- Michal Sojka <sojkam1@fel.cvut.cz>
- Miles Bader <miles@gnu.org>
- Miloš Mošić <mosic.milos@gmail.com>
- Mitchel Humpherys <mitch.special@gmail.com>
- Moritz Bunkus <moritz@bunkus.org>
- Natalie Weizenbaum <nex342@gmail.com>
- Nguyễn Tuấn Anh <ubolonton@gmail.com>
- Nic Ferier <nic@ferrier.me.uk>
- Nick Alcock <nick.alcock@oracle.com>
- Nick Alexander <nalexander@mozilla.com>
- Nick Dimiduk <ndimiduk@gmail.com>
- Nicklas Lindgren <nili@gulmohar.se>
- Nicolas Dudebout <nicolas.dudebout@gatech.edu>
- Nicolas Petton <nicolas@petton.fr>
- Nicolas Richard <theonewiththeevillook@yahoo.fr>
- Nikolay Martynov <mar.kolya@gmail.com>
- Noam Postavsky <npostavs@users.sourceforge.net>
- Ole Arndt <oliver.arndt@cegedim.com>
- Oleh Krehel <ohwoeowho@gmail.com>
- Óscar Fuentes <ofv@wanadoo.es>
- Paul Stadig <paul@stadig.name>
- Pavel Holejsovsky <pavel.holejsovsky@upek.com>
- Pekka Pessi <nospam@pessi.fi>
- Peter Eisentraut <peter@eisentraut.org>
- Peter Jaros <peter.a.jaros@gmail.com>
- Peter J. Weisberg <pj@irregularexpressions.net>
- Peter Vasil <mail@petervasil.net>
- Philippe Vaucher <philippe.vaucher@gmail.com>
- Philipp Haselwarter <philipp@haselwarter.org>
- Philipp Stephani <phst@google.com>
- Philip Weaver <philip.weaver@gmail.com>
- Phil Jackson <phil@shellarchive.co.uk>
- Phil Sainty <phil@catalyst.net.nz>
- Pieter Praet <pieter@praet.org>
- Prathamesh Sonpatki <csonpatki@gmail.com>
- rabio <rabiodev@o2.pl>
- Radon Rosborough <radon.neon@gmail.com>
- Rafael Laboissiere <rafael@laboissiere.net>
- Raimon Grau <raimon@3scale.net>
- Ramkumar Ramachandra <artagnon@gmail.com>
- Remco van 't Veer <rwvtveer@xs4all.nl>
- Rémi Vanicat <vanicat@debian.org>
- René Stadler <mail@renestadler.de>
- Richard Kim <emacs18@gmail.com>
- Robert Boone <robo4288@gmail.com>
- Robin Green <greenrd@greenrd.org>
- Roger Crew <crew@cs.stanford.edu>
- Romain Francoise <romain@orebokech.com>
- Ron Parker <rparker@a123systems.com>
- Roy Crihfield <rscrihf@gmail.com>
- Rüdiger Sonderfeld <ruediger@c-plusplus.net>
- Russell Black <black.russell@gmail.com>
- Ryan C. Thompson <rct@thompsonclan.org>
- Samuel Bronson <naesten@gmail.com>
- Samuel W. Flint <swflint@flintfam.org>
- Sanjoy Das <sanjoy@playingwithpointers.com>
- Sean Allred <code@seanallred.com>
- Sean Bryant <sbryant@hackinggibsons.com>
- Sean Whitton <spwhitton@spwhitton.name>
- Sebastian Wiesner <lunaryorn@gmail.com>
- Sébastien Gross <seb@chezwam.org>
- Seong-Kook Shin <cinsky@gmail.com>
- Sergey Pashinin <sergey@pashinin.com>
- Sergey Vinokurov <serg.foo@gmail.com>
- Servilio Afre Puentes <afrepues@mcmaster.ca>
- Silent Sphere <silentsphere110@gmail.com>
- Štěpán Němec <stepnem@gmail.com>
- Steven Chow <steve@myfreestuffapp.com>
- Steven E. Harris <seh@panix.com>
- Steven Thomas <sthomas314@gmail.com>
- Steven Vancoillie <steven.vancoillie@runbox.com>
- Steve Purcell <steve@sanityinc.com>
- Suhail Shergill <suhailshergill@gmail.com>
- Sylvain Rousseau <thisirs@gmail.com>
- Syohei Yoshida <syohex@gmail.com>
- Takafumi Arakaki <aka.tkf@gmail.com>
- Teemu Likonen <tlikonen@iki.fi>
- Teruki Shigitani <teruki.shigitani@gmail.com>
- Thierry Volpiatto <thierry.volpiatto@gmail.com>
- Thomas A Caswell <tcaswell@gmail.com>
- Thomas Frössman <thomasf@jossystem.se>
- Thomas Jost <thomas.jost@gmail.com>
- Thomas Riccardi <riccardi.thomas@gmail.com>
- Tibor Simko <tibor.simko@cern.ch>
- Timo Juhani Lindfors <timo.lindfors@iki.fi>
- Tim Perkins <tprk77@gmail.com>
- Tim Wraight <tim@wraight.net>
- Ting-Yu Lin <aethanyc@gmail.com>
- Tom Feist <shabble@metavore.org>
- Tunc Uzlu <bb2020@users.noreply.github.com>
- Vineet Naik <vineet@helpshift.com>
- Wei Huang <weih@opera.com>
- Wilfred Hughes <me@wilfred.me.uk>
- Win Treese <treese@acm.org>
- Wouter Bolsterlee <wouter@bolsterl.ee>
- Xavier Noria <fxn@hashref.com>
- Yann Hodique <yann.hodique@gmail.com>
- York Zhao <gtdplatform@gmail.com>
- Yuichi Higashi <aaa707b@gmail.com>
- Yuri Khan <yurivkhan@gmail.com>
- Zach Latta <zach@zachlatta.com>

View File

@ -1,676 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -1,18 +0,0 @@
This is the file .../info/dir, which contains the
topmost node of the Info hierarchy, called (dir)Top.
The first time you invoke Info you start off looking at this node.

File: dir, Node: Top This is the top of the INFO tree
This (the Directory node) gives a menu of major topics.
Typing "q" exits, "?" lists all Info commands, "d" returns here,
"h" gives a primer for first-timers,
"mEmacs<Return>" visits the Emacs manual, etc.
In Emacs, you can click mouse button 2 on a menu item or cross reference
to select it.
* Menu:
Emacs
* Magit: (magit). Using Git from Emacs with Magit.

View File

@ -1,586 +0,0 @@
;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding: t -*-
;; Copyright (C) 2010-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Phil Jackson <phil@shellarchive.co.uk>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; This file is not part of GNU Emacs.
;; This file 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 file 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 file. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This package assists the user in editing the list of commits to be
;; rewritten during an interactive rebase.
;; When the user initiates an interactive rebase, e.g. using "r e" in
;; a Magit buffer or on the command line using "git rebase -i REV",
;; Git invokes the `$GIT_SEQUENCE_EDITOR' (or if that is undefined
;; `$GIT_EDITOR' or even `$EDITOR') letting the user rearrange, drop,
;; reword, edit, and squash commits.
;; This package provides the major-mode `git-rebase-mode' which makes
;; doing so much more fun, by making the buffer more colorful and
;; providing the following commands:
;;
;; C-c C-c Tell Git to make it happen.
;; C-c C-k Tell Git that you changed your mind, i.e. abort.
;;
;; p Move point to previous line.
;; n Move point to next line.
;;
;; M-p Move the commit at point up.
;; M-n Move the commit at point down.
;;
;; k Drop the commit at point.
;; c Don't drop the commit at point.
;; r Change the message of the commit at point.
;; e Edit the commit at point.
;; s Squash the commit at point, into the one above.
;; f Like "s" but don't also edit the commit message.
;; x Add a script to be run with the commit at point
;; being checked out.
;; z Add noop action at point.
;;
;; SPC Show the commit at point in another buffer.
;; RET Show the commit at point in another buffer and
;; select its window.
;; C-/ Undo last change.
;; You should probably also read the `git-rebase' manpage.
;;; Code:
(require 'dash)
(require 'easymenu)
(require 'server)
(require 'with-editor)
(require 'magit)
(and (require 'async-bytecomp nil t)
(memq 'magit (bound-and-true-p async-bytecomp-allowed-packages))
(fboundp 'async-bytecomp-package-mode)
(async-bytecomp-package-mode 1))
(eval-when-compile (require 'recentf))
;;; Options
;;;; Variables
(defgroup git-rebase nil
"Edit Git rebase sequences."
:link '(info-link "(magit)Editing Rebase Sequences")
:group 'tools)
(defcustom git-rebase-auto-advance t
"Whether to move to next line after changing a line."
:group 'git-rebase
:type 'boolean)
(defcustom git-rebase-show-instructions t
"Whether to show usage instructions inside the rebase buffer."
:group 'git-rebase
:type 'boolean)
(defcustom git-rebase-confirm-cancel t
"Whether confirmation is required to cancel."
:group 'git-rebase
:type 'boolean)
;;;; Faces
(defgroup git-rebase-faces nil
"Faces used by Git-Rebase mode."
:group 'faces
:group 'git-rebase)
(defface git-rebase-hash '((t (:inherit magit-hash)))
"Face for commit hashes."
:group 'git-rebase-faces)
(defface git-rebase-description nil
"Face for commit descriptions."
:group 'git-rebase-faces)
(defface git-rebase-killed-action
'((t (:inherit font-lock-comment-face :strike-through t)))
"Face for commented action and exec lines."
:group 'git-rebase-faces)
(defface git-rebase-comment-hash
'((t (:inherit git-rebase-hash :weight bold)))
"Face for commit hashes in commit message comments."
:group 'git-rebase-faces)
(defface git-rebase-comment-heading
'((t :inherit font-lock-keyword-face))
"Face for headings in rebase message comments."
:group 'git-commit-faces)
;;; Keymaps
(defvar git-rebase-mode-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map special-mode-map)
(cond ((featurep 'jkl)
(define-key map [return] 'git-rebase-show-commit)
(define-key map (kbd "i") 'git-rebase-backward-line)
(define-key map (kbd "k") 'forward-line)
(define-key map (kbd "M-i") 'git-rebase-move-line-up)
(define-key map (kbd "M-k") 'git-rebase-move-line-down)
(define-key map (kbd "p") 'git-rebase-pick)
(define-key map (kbd ",") 'git-rebase-kill-line))
(t
(define-key map (kbd "C-m") 'git-rebase-show-commit)
(define-key map (kbd "p") 'git-rebase-backward-line)
(define-key map (kbd "n") 'forward-line)
(define-key map (kbd "M-p") 'git-rebase-move-line-up)
(define-key map (kbd "M-n") 'git-rebase-move-line-down)
(define-key map (kbd "c") 'git-rebase-pick)
(define-key map (kbd "k") 'git-rebase-kill-line)
(define-key map (kbd "C-k") 'git-rebase-kill-line)))
(define-key map (kbd "e") 'git-rebase-edit)
(define-key map (kbd "m") 'git-rebase-edit)
(define-key map (kbd "f") 'git-rebase-fixup)
(define-key map (kbd "q") 'undefined)
(define-key map (kbd "r") 'git-rebase-reword)
(define-key map (kbd "w") 'git-rebase-reword)
(define-key map (kbd "s") 'git-rebase-squash)
(define-key map (kbd "x") 'git-rebase-exec)
(define-key map (kbd "y") 'git-rebase-insert)
(define-key map (kbd "z") 'git-rebase-noop)
(define-key map (kbd "SPC") 'git-rebase-show-or-scroll-up)
(define-key map (kbd "DEL") 'git-rebase-show-or-scroll-down)
(define-key map (kbd "C-x C-t") 'git-rebase-move-line-up)
(define-key map [M-up] 'git-rebase-move-line-up)
(define-key map [M-down] 'git-rebase-move-line-down)
(define-key map [remap undo] 'git-rebase-undo)
map)
"Keymap for Git-Rebase mode.")
(cond ((featurep 'jkl)
(put 'git-rebase-reword :advertised-binding "r")
(put 'git-rebase-move-line-up :advertised-binding (kbd "M-i"))
(put 'git-rebase-kill-line :advertised-binding ","))
(t
(put 'git-rebase-reword :advertised-binding "r")
(put 'git-rebase-move-line-up :advertised-binding (kbd "M-p"))
(put 'git-rebase-kill-line :advertised-binding "k")))
(easy-menu-define git-rebase-mode-menu git-rebase-mode-map
"Git-Rebase mode menu"
'("Rebase"
["Pick" git-rebase-pick t]
["Reword" git-rebase-reword t]
["Edit" git-rebase-edit t]
["Squash" git-rebase-squash t]
["Fixup" git-rebase-fixup t]
["Kill" git-rebase-kill-line t]
["Execute" git-rebase-exec t]
["Move Down" git-rebase-move-line-down t]
["Move Up" git-rebase-move-line-up t]
"---"
["Cancel" with-editor-cancel t]
["Finish" with-editor-finish t]))
(defvar git-rebase-command-descriptions
'((with-editor-finish . "tell Git to make it happen")
(with-editor-cancel . "tell Git that you changed your mind, i.e. abort")
(git-rebase-backward-line . "move point to previous line")
(forward-line . "move point to next line")
(git-rebase-move-line-up . "move the commit at point up")
(git-rebase-move-line-down . "move the commit at point down")
(git-rebase-show-or-scroll-up . "show the commit at point in another buffer")
(git-rebase-show-commit
. "show the commit at point in another buffer and select its window")
(undo . "undo last change")
(git-rebase-kill-line . "drop the commit at point")
(git-rebase-insert . "insert a line for an arbitrary commit")
(git-rebase-noop . "add noop action at point")))
;;; Commands
(defun git-rebase-pick ()
"Use commit on current line."
(interactive)
(git-rebase-set-action "pick"))
(defun git-rebase-reword ()
"Edit message of commit on current line."
(interactive)
(git-rebase-set-action "reword"))
(defun git-rebase-edit ()
"Stop at the commit on the current line."
(interactive)
(git-rebase-set-action "edit"))
(defun git-rebase-squash ()
"Meld commit on current line into previous commit, edit message."
(interactive)
(git-rebase-set-action "squash"))
(defun git-rebase-fixup ()
"Meld commit on current line into previous commit, discard its message."
(interactive)
(git-rebase-set-action "fixup"))
(defvar-local git-rebase-line nil)
(defvar-local git-rebase-comment-re nil)
(defun git-rebase-set-action (action)
(goto-char (line-beginning-position))
(if (and (looking-at git-rebase-line)
(not (string-match-p "\\(e\\|exec\\|noop\\)$" (match-string 1))))
(let ((inhibit-read-only t))
(replace-match action t t nil 1)
(when git-rebase-auto-advance
(forward-line)))
(ding)))
(defun git-rebase-line-p (&optional pos)
(save-excursion
(when pos (goto-char pos))
(goto-char (line-beginning-position))
(looking-at-p git-rebase-line)))
(defun git-rebase-region-bounds ()
(when (use-region-p)
(let ((beg (save-excursion (goto-char (region-beginning))
(line-beginning-position)))
(end (save-excursion (goto-char (region-end))
(line-end-position))))
(when (and (git-rebase-line-p beg)
(git-rebase-line-p end))
(list beg (1+ end))))))
(defun git-rebase-move-line-down (n)
"Move the current commit (or command) N lines down.
If N is negative, move the commit up instead. With an active
region, move all the lines that the region touches, not just the
current line."
(interactive "p")
(-let* (((beg end) (or (git-rebase-region-bounds)
(list (line-beginning-position)
(1+ (line-end-position)))))
(pt-offset (- (point) beg))
(mark-offset (and mark-active (- (mark) beg))))
(save-restriction
(narrow-to-region
(point-min)
(1+ (save-excursion
(goto-char (point-min))
(while (re-search-forward git-rebase-line nil t))
(point))))
(if (or (and (< n 0) (= beg (point-min)))
(and (> n 0) (= end (point-max)))
(> end (point-max)))
(ding)
(goto-char (if (< n 0) beg end))
(forward-line n)
(atomic-change-group
(let ((inhibit-read-only t))
(insert (delete-and-extract-region beg end)))
(let ((new-beg (- (point) (- end beg))))
(when (use-region-p)
(setq deactivate-mark nil)
(set-mark (+ new-beg mark-offset)))
(goto-char (+ new-beg pt-offset))))))))
(defun git-rebase-move-line-up (n)
"Move the current commit (or command) N lines up.
If N is negative, move the commit down instead. With an active
region, move all the lines that the region touches, not just the
current line."
(interactive "p")
(git-rebase-move-line-down (- n)))
(defun git-rebase-highlight-region (start end window rol)
(let ((inhibit-read-only t)
(deactivate-mark nil)
(bounds (git-rebase-region-bounds)))
(mapc #'delete-overlay magit-section-highlight-overlays)
(when bounds
(magit-section-make-overlay (car bounds) (cadr bounds)
'magit-section-heading-selection))
(if (and bounds (not magit-keep-region-overlay))
(funcall (default-value 'redisplay-unhighlight-region-function) rol)
(funcall (default-value 'redisplay-highlight-region-function)
start end window rol))))
(defun git-rebase-unhighlight-region (rol)
(mapc #'delete-overlay magit-section-highlight-overlays)
(funcall (default-value 'redisplay-unhighlight-region-function) rol))
(defun git-rebase-kill-line ()
"Kill the current action line."
(interactive)
(goto-char (line-beginning-position))
(when (and (looking-at git-rebase-line)
(not (eq (char-after) (string-to-char comment-start))))
(let ((inhibit-read-only t))
(insert comment-start)
(insert " "))
(when git-rebase-auto-advance
(forward-line))))
(defun git-rebase-insert (rev)
"Read an arbitrary commit and insert it below current line."
(interactive (list (magit-read-branch-or-commit "Insert revision")))
(forward-line)
(--if-let (magit-rev-format "%h %s" rev)
(let ((inhibit-read-only t))
(insert "pick " it ?\n))
(user-error "Unknown revision")))
(defun git-rebase-exec (arg)
"Insert a shell command to be run after the proceeding commit.
If there already is such a command on the current line, then edit
that instead. With a prefix argument insert a new command even
when there already is one on the current line. With empty input
remove the command on the current line, if any."
(interactive "P")
(let ((inhibit-read-only t) initial command)
(unless arg
(goto-char (line-beginning-position))
(when (looking-at (concat git-rebase-comment-re "?"
"\\(e\\|exec\\) \\(.*\\)"))
(setq initial (match-string-no-properties 2))))
(setq command (read-shell-command "Execute: " initial))
(pcase (list command initial)
(`("" nil) (ding))
(`("" ,_)
(delete-region (match-beginning 0) (1+ (match-end 0))))
(`(,_ nil)
(forward-line)
(insert (concat "exec " command "\n"))
(unless git-rebase-auto-advance
(forward-line -1)))
(_
(replace-match (concat "exec " command) t t)
(if git-rebase-auto-advance
(forward-line)
(goto-char (line-beginning-position)))))))
(defun git-rebase-noop (&optional arg)
"Add noop action at point.
If the current line already contains a a noop action, leave it
unchanged. If there is a commented noop action present, remove
the comment. Otherwise add a new noop action. With a prefix
argument insert a new noop action regardless what is already
present on the current line.
A noop action can be used to make git perform a rebase even if
no commits are selected. Without the noop action present, git
would see an empty file and therefore do nothing."
(interactive "P")
(goto-char (line-beginning-position))
;; The extra space at the end is only there to make the action
;; consistent with the others (action argument). This keeps
;; the regexp `git-rebase-line' from getting complicated.
(let ((noop-string "noop \n"))
(when (or arg (not (looking-at noop-string)))
(let ((inhibit-read-only t))
(if (and (not arg)
(looking-at (concat comment-start noop-string)))
(delete-char 1)
(insert noop-string))))))
(defun git-rebase-undo (&optional arg)
"Undo some previous changes.
Like `undo' but works in read-only buffers."
(interactive "P")
(let ((inhibit-read-only t))
(undo arg)))
(defun git-rebase--show-commit (&optional scroll)
(let ((disable-magit-save-buffers t))
(save-excursion
(goto-char (line-beginning-position))
(--if-let (and (looking-at git-rebase-line)
(match-string 2))
(pcase scroll
(`up (magit-diff-show-or-scroll-up))
(`down (magit-diff-show-or-scroll-down))
(_ (apply #'magit-show-commit it (magit-diff-arguments))))
(ding)))))
(defun git-rebase-show-commit ()
"Show the commit on the current line if any."
(interactive)
(git-rebase--show-commit))
(defun git-rebase-show-or-scroll-up ()
"Update the commit buffer for commit on current line.
Either show the commit at point in the appropriate buffer, or if
that buffer is already being displayed in the current frame and
contains information about that commit, then instead scroll the
buffer up."
(interactive)
(git-rebase--show-commit 'up))
(defun git-rebase-show-or-scroll-down ()
"Update the commit buffer for commit on current line.
Either show the commit at point in the appropriate buffer, or if
that buffer is already being displayed in the current frame and
contains information about that commit, then instead scroll the
buffer down."
(interactive)
(git-rebase--show-commit 'down))
(defun git-rebase-backward-line (&optional n)
"Move N lines backward (forward if N is negative).
Like `forward-line' but go into the opposite direction."
(interactive "p")
(forward-line (- (or n 1))))
;;; Mode
;;;###autoload
(define-derived-mode git-rebase-mode special-mode "Git Rebase"
"Major mode for editing of a Git rebase file.
Rebase files are generated when you run 'git rebase -i' or run
`magit-interactive-rebase'. They describe how Git should perform
the rebase. See the documentation for git-rebase (e.g., by
running 'man git-rebase' at the command line) for details."
:group 'git-rebase
(setq comment-start (or (magit-get "core.commentChar") "#"))
(setq git-rebase-comment-re (concat "^" (regexp-quote comment-start)))
(setq git-rebase-line
(concat "^\\(" (regexp-quote comment-start) "? *"
"\\(?:[fprse]\\|pick\\|reword\\|edit\\|squash\\|fixup\\|exec\\|noop\\)\\) "
"\\(?:\\([^ \n]+\\) \\(.*\\)\\)?"))
(setq font-lock-defaults (list (git-rebase-mode-font-lock-keywords) t t))
(unless git-rebase-show-instructions
(let ((inhibit-read-only t))
(flush-lines git-rebase-comment-re)))
(unless with-editor-mode
;; Maybe already enabled when using `shell-command' or an Emacs shell.
(with-editor-mode 1))
(when git-rebase-confirm-cancel
(add-hook 'with-editor-cancel-query-functions
'git-rebase-cancel-confirm nil t))
(setq-local redisplay-highlight-region-function 'git-rebase-highlight-region)
(setq-local redisplay-unhighlight-region-function 'git-rebase-unhighlight-region)
(add-hook 'with-editor-pre-cancel-hook 'git-rebase-autostash-save nil t)
(add-hook 'with-editor-post-cancel-hook 'git-rebase-autostash-apply nil t)
(setq imenu-prev-index-position-function
#'magit-imenu--rebase-prev-index-position-function)
(setq imenu-extract-index-name-function
#'magit-imenu--rebase-extract-index-name-function)
(when (boundp 'save-place)
(setq save-place nil)))
(defun git-rebase-cancel-confirm (force)
(or (not (buffer-modified-p))
force
(magit-confirm 'abort-rebase "Abort this rebase")))
(defun git-rebase-autostash-save ()
(--when-let (magit-file-line (magit-git-dir "rebase-merge/autostash"))
(push (cons 'stash it) with-editor-cancel-alist)))
(defun git-rebase-autostash-apply ()
(--when-let (cdr (assq 'stash with-editor-cancel-alist))
(magit-stash-apply it)))
(defun git-rebase-match-comment-line (limit)
(re-search-forward (concat git-rebase-comment-re ".*") limit t))
(defun git-rebase-mode-font-lock-keywords ()
"Font lock keywords for Git-Rebase mode."
(let ((action-re "\
\\([efprs]\\|pick\\|reword\\|edit\\|squash\\|fixup\\) \\([^ \n]+\\) \\(.*\\)"))
`((,(concat "^" action-re)
(1 'font-lock-keyword-face)
(2 'git-rebase-hash)
(3 'git-rebase-description))
("^\\(exec\\) \\(.*\\)"
(1 'font-lock-keyword-face)
(2 'git-rebase-description))
(git-rebase-match-comment-line 0 'font-lock-comment-face)
(,(concat git-rebase-comment-re " *" action-re)
0 'git-rebase-killed-action t)
(,(format "^%s Rebase \\([^ ]*\\) onto \\([^ ]*\\)" comment-start)
(1 'git-rebase-comment-hash t)
(2 'git-rebase-comment-hash t))
(,(format "^%s \\(Commands:\\)" comment-start)
(1 'git-rebase-comment-heading t)))))
(defun git-rebase-mode-show-keybindings ()
"Modify the \"Commands:\" section of the comment Git generates
at the bottom of the file so that in place of the one-letter
abbreviation for the command, it shows the command's keybinding.
By default, this is the same except for the \"pick\" command."
(let ((inhibit-read-only t))
(save-excursion
(goto-char (point-min))
(when (and git-rebase-show-instructions
(re-search-forward
(concat git-rebase-comment-re " p, pick")
nil t))
(goto-char (line-beginning-position))
(--each git-rebase-command-descriptions
(insert (format "%s %-8s %s\n"
comment-start
(substitute-command-keys (format "\\[%s]" (car it)))
(cdr it))))
(while (re-search-forward (concat git-rebase-comment-re
"\\( ?\\)\\([^\n,],\\) "
"\\([^\n ]+\\) ")
nil t)
(let ((cmd (intern (concat "git-rebase-" (match-string 3)))))
(if (not (fboundp cmd))
(delete-region (line-beginning-position) (1+ (line-end-position)))
(replace-match " " t t nil 1)
(replace-match
(format "%-8s"
(mapconcat #'key-description
(--filter (not (eq (elt it 0) 'menu-bar))
(reverse (where-is-internal cmd)))
", "))
t t nil 2))))))))
(add-hook 'git-rebase-mode-hook 'git-rebase-mode-show-keybindings t)
(defun git-rebase-mode-disable-before-save-hook ()
(set (make-local-variable 'before-save-hook) nil))
(add-hook 'git-rebase-mode-hook 'git-rebase-mode-disable-before-save-hook)
;;;###autoload
(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
;;;###autoload
(add-to-list 'auto-mode-alist
(cons git-rebase-filename-regexp 'git-rebase-mode))
(add-to-list 'with-editor-server-window-alist
(cons git-rebase-filename-regexp 'switch-to-buffer))
(eval-after-load 'recentf
'(add-to-list 'recentf-exclude git-rebase-filename-regexp))
(add-to-list 'with-editor-file-name-history-exclude git-rebase-filename-regexp)
(provide 'git-rebase)
;;; git-rebase.el ends here

View File

@ -1,641 +0,0 @@
;;; magit-apply.el --- apply Git diffs -*- lexical-binding: t -*-
;; Copyright (C) 2010-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; This library implements commands for applying Git diffs or parts
;; of such a diff. The supported "apply variants" are apply, stage,
;; unstage, discard, and reverse - more than Git itself knows about,
;; at least at the porcelain level.
;;; Code:
(require 'magit-core)
(require 'magit-diff)
(require 'magit-wip)
;; For `magit-apply'
(declare-function magit-am-popup 'magit-sequence)
(declare-function magit-patch-apply-popup 'magit-files)
;; For `magit-discard-files'
(declare-function magit-checkout-stage 'magit)
(declare-function magit-checkout-read-stage 'magit)
(defvar auto-revert-verbose)
;; For `magit-stage-untracked'
(declare-function magit-submodule-add 'magit-submodule)
(declare-function magit-submodule-read-name-for-path 'magit-submodule)
(declare-function borg--maybe-absorb-gitdir 'borg)
(declare-function borg--sort-submodule-sections 'borg)
(defvar borg-user-emacs-directory)
(require 'dired)
;;; Options
(defcustom magit-delete-by-moving-to-trash t
"Whether Magit uses the system's trash can.
You should absolutely not disable this and also remove `discard'
from `magit-no-confirm'. You shouldn't do that even if you have
all of the Magit-Wip modes enabled, because those modes do not
track any files that are not tracked in the proper branch."
:package-version '(magit . "2.1.0")
:group 'magit-essentials
:type 'boolean)
(defcustom magit-unstage-committed t
"Whether unstaging a committed change reverts it instead.
A committed change cannot be unstaged, because staging and
unstaging are actions that are concerned with the differences
between the index and the working tree, not with committed
changes.
If this option is non-nil (the default), then typing \"u\"
\(`magit-unstage') on a committed change, causes it to be
reversed in the index but not the working tree. For more
information see command `magit-reverse-in-index'."
:package-version '(magit . "2.4.1")
:group 'magit-commands
:type 'boolean)
(defcustom magit-reverse-atomically nil
"Whether to reverse changes atomically.
If some changes can be reversed while others cannot, then nothing
is reversed if the value of this option is non-nil. But when it
is nil, then the changes that can be reversed are reversed and
for the other changes diff files are created that contain the
rejected reversals."
:package-version '(magit . "2.7.0")
:group 'magit-commands
:type 'boolean)
;;; Commands
;;;; Apply
(defun magit-apply (&rest args)
"Apply the change at point to the working tree.
With a prefix argument fallback to a 3-way merge. Doing
so causes the change to be applied to the index as well."
(interactive (and current-prefix-arg (list "--3way")))
(--when-let (magit-apply--get-selection)
(pcase (list (magit-diff-type) (magit-diff-scope))
(`(,(or `unstaged `staged) ,_)
(user-error "Change is already in the working tree"))
(`(untracked ,(or `file `files))
(magit-am-popup))
(`(,_ region) (magit-apply-region it args))
(`(,_ hunk) (magit-apply-hunk it args))
(`(,_ hunks) (magit-apply-hunks it args))
(`(rebase-sequence file) (magit-patch-apply-popup))
(`(,_ file) (magit-apply-diff it args))
(`(,_ files) (magit-apply-diffs it args)))))
(defun magit-apply--section-content (section)
(buffer-substring-no-properties (if (eq (magit-section-type section) 'hunk)
(magit-section-start section)
(magit-section-content section))
(magit-section-end section)))
(defun magit-apply-diffs (sections &rest args)
(setq sections (magit-apply--get-diffs sections))
(magit-apply-patch sections args
(mapconcat
(lambda (s)
(concat (magit-diff-file-header s)
(magit-apply--section-content s)))
sections "")))
(defun magit-apply-diff (section &rest args)
(setq section (car (magit-apply--get-diffs (list section))))
(magit-apply-patch section args
(concat (magit-diff-file-header section)
(magit-apply--section-content section))))
(defun magit-apply-hunks (sections &rest args)
(let ((section (magit-section-parent (car sections))))
(when (string-match "^diff --cc" (magit-section-value section))
(user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
(magit-apply-patch section args
(concat (magit-section-diff-header section)
(mapconcat 'magit-apply--section-content
sections "")))))
(defun magit-apply-hunk (section &rest args)
(when (string-match "^diff --cc" (magit-section-parent-value section))
(user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
(magit-apply-patch (magit-section-parent section) args
(concat (magit-diff-file-header section)
(magit-apply--section-content section))))
(defun magit-apply-region (section &rest args)
(unless (magit-diff-context-p)
(user-error "Not enough context to apply region. Increase the context"))
(when (string-match "^diff --cc" (magit-section-parent-value section))
(user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
(magit-apply-patch (magit-section-parent section) args
(concat (magit-diff-file-header section)
(magit-diff-hunk-region-patch section args))))
(defun magit-apply-patch (section:s args patch)
(let* ((files (if (atom section:s)
(list (magit-section-value section:s))
(mapcar 'magit-section-value section:s)))
(command (symbol-name this-command))
(command (if (and command (string-match "^magit-\\([^-]+\\)" command))
(match-string 1 command)
"apply")))
(when (and magit-wip-before-change-mode (not inhibit-magit-refresh))
(magit-wip-commit-before-change files (concat " before " command)))
(with-temp-buffer
(insert patch)
(magit-run-git-with-input
"apply" args "-p0"
(unless (magit-diff-context-p) "--unidiff-zero")
"--ignore-space-change" "-"))
(unless inhibit-magit-refresh
(when magit-wip-after-apply-mode
(magit-wip-commit-after-apply files (concat " after " command)))
(magit-refresh))))
(defun magit-apply--get-selection ()
(or (magit-region-sections '(hunk file) t)
(let ((section (magit-current-section)))
(pcase (magit-section-type section)
((or `hunk `file) section)
((or `staged `unstaged `untracked
`stashed-index `stashed-worktree `stashed-untracked)
(magit-section-children section))
(_ (user-error "Cannot apply this, it's not a change"))))))
(defun magit-apply--get-diffs (sections)
(magit-section-case
([file diffstat]
(--map (or (magit-get-section
(append `((file . ,(magit-section-value it)))
(magit-section-ident magit-root-section)))
(error "Cannot get required diff headers"))
sections))
(t sections)))
(defun magit-apply--diff-ignores-whitespace-p ()
(and (cl-intersection (if (derived-mode-p 'magit-diff-mode)
(nth 2 magit-refresh-args)
magit-diff-section-arguments)
'("--ignore-space-at-eol"
"--ignore-space-change"
"--ignore-all-space"
"--ignore-blank-lines")
:test #'equal)
t))
;;;; Stage
(defun magit-stage (&optional intent)
"Add the change at point to the staging area.
With a prefix argument, INTENT, and an untracked file (or files)
at point, stage the file but not its content."
(interactive "P")
(--if-let (and (derived-mode-p 'magit-mode) (magit-apply--get-selection))
(pcase (list (magit-diff-type)
(magit-diff-scope)
(magit-apply--diff-ignores-whitespace-p))
(`(untracked ,_ ,_) (magit-stage-untracked intent))
(`(unstaged region ,_) (magit-apply-region it "--cached"))
(`(unstaged hunk ,_) (magit-apply-hunk it "--cached"))
(`(unstaged hunks ,_) (magit-apply-hunks it "--cached"))
(`(unstaged file t) (magit-apply-diff it "--cached"))
(`(unstaged files t) (magit-apply-diffs it "--cached"))
(`(unstaged list t) (magit-apply-diffs it "--cached"))
(`(unstaged file nil) (magit-stage-1 "-u" (list (magit-section-value it))))
(`(unstaged files nil) (magit-stage-1 "-u" (magit-region-values nil t)))
(`(unstaged list nil) (magit-stage-modified))
(`(staged ,_ ,_) (user-error "Already staged"))
(`(committed ,_ ,_) (user-error "Cannot stage committed changes"))
(`(undefined ,_ ,_) (user-error "Cannot stage this change")))
(call-interactively 'magit-stage-file)))
;;;###autoload
(defun magit-stage-file (file)
"Stage all changes to FILE.
With a prefix argument or when there is no file at point ask for
the file to be staged. Otherwise stage the file at point without
requiring confirmation."
(interactive
(let* ((atpoint (magit-section-when (file)))
(current (magit-file-relative-name))
(choices (nconc (magit-unstaged-files)
(magit-untracked-files)))
(default (car (member (or atpoint current) choices))))
(list (if (or current-prefix-arg (not default))
(magit-completing-read "Stage file" choices
nil t nil nil default)
default))))
(magit-with-toplevel
(magit-stage-1 nil (list file))))
;;;###autoload
(defun magit-stage-modified (&optional all)
"Stage all changes to files modified in the worktree.
Stage all new content of tracked files and remove tracked files
that no longer exist in the working tree from the index also.
With a prefix argument also stage previously untracked (but not
ignored) files."
(interactive "P")
(when (magit-anything-staged-p)
(unless (magit-confirm 'stage-all-changes)
(user-error "Abort")))
(magit-with-toplevel
(magit-stage-1 (if all "--all" "-u"))))
(defun magit-stage-1 (arg &optional files)
(magit-wip-commit-before-change files " before stage")
(magit-run-git "add" arg (if files (cons "--" files) "."))
(when magit-auto-revert-mode
(mapc #'magit-turn-on-auto-revert-mode-if-desired files))
(magit-wip-commit-after-apply files " after stage"))
(defun magit-stage-untracked (&optional intent)
(let* ((section (magit-current-section))
(files (pcase (magit-diff-scope)
(`file (list (magit-section-value section)))
(`files (magit-region-values nil t))
(`list (magit-untracked-files))))
plain repos)
(dolist (file files)
(if (and (not (file-symlink-p file))
(magit-git-repo-p file t))
(push file repos)
(push file plain)))
(magit-wip-commit-before-change files " before stage")
(when plain
(magit-run-git "add" (and intent "--intent-to-add")
"--" plain)
(when magit-auto-revert-mode
(mapc #'magit-turn-on-auto-revert-mode-if-desired plain)))
(dolist (repo repos)
(save-excursion
(goto-char (magit-section-start
(magit-get-section
`((file . ,repo) (untracked) (status)))))
(let* ((topdir (magit-toplevel))
(package
(and (equal (bound-and-true-p borg-user-emacs-directory)
topdir)
(file-name-nondirectory (directory-file-name repo)))))
(magit-submodule-add
(let ((default-directory
(file-name-as-directory (expand-file-name repo))))
(or (magit-get "remote" (magit-get-some-remote) "url")
(concat (file-name-as-directory ".") repo)))
repo
(magit-submodule-read-name-for-path repo package))
(when package
(borg--sort-submodule-sections
(expand-file-name ".gitmodules" topdir))
(let ((default-directory borg-user-emacs-directory))
(borg--maybe-absorb-gitdir package))
(when (and (y-or-n-p
(format "Also build and activate `%s' drone?" package))
(fboundp 'borg-build)
(fboundp 'borg-activate))
(borg-build package)
(borg-activate package))))))
(magit-wip-commit-after-apply files " after stage")))
;;;; Unstage
(defun magit-unstage ()
"Remove the change at point from the staging area."
(interactive)
(--when-let (magit-apply--get-selection)
(pcase (list (magit-diff-type)
(magit-diff-scope)
(magit-apply--diff-ignores-whitespace-p))
(`(untracked ,_ ,_) (user-error "Cannot unstage untracked changes"))
(`(unstaged ,_ ,_) (user-error "Already unstaged"))
(`(staged region ,_) (magit-apply-region it "--reverse" "--cached"))
(`(staged hunk ,_) (magit-apply-hunk it "--reverse" "--cached"))
(`(staged hunks ,_) (magit-apply-hunks it "--reverse" "--cached"))
(`(staged file t) (magit-apply-diff it "--reverse" "--cached"))
(`(staged files t) (magit-apply-diffs it "--reverse" "--cached"))
(`(staged list t) (magit-apply-diffs it "--reverse" "--cached"))
(`(staged file nil) (magit-unstage-1 (list (magit-section-value it))))
(`(staged files nil) (magit-unstage-1 (magit-region-values nil t)))
(`(staged list nil) (magit-unstage-all))
(`(committed ,_ ,_) (if magit-unstage-committed
(magit-reverse-in-index)
(user-error "Cannot unstage committed changes")))
(`(undefined ,_ ,_) (user-error "Cannot unstage this change")))))
;;;###autoload
(defun magit-unstage-file (file)
"Unstage all changes to FILE.
With a prefix argument or when there is no file at point ask for
the file to be unstaged. Otherwise unstage the file at point
without requiring confirmation."
(interactive
(let* ((atpoint (magit-section-when (file)))
(current (magit-file-relative-name))
(choices (magit-staged-files))
(default (car (member (or atpoint current) choices))))
(list (if (or current-prefix-arg (not default))
(magit-completing-read "Unstage file" choices
nil t nil nil default)
default))))
(magit-with-toplevel
(magit-unstage-1 (list file))))
(defun magit-unstage-1 (files)
(magit-wip-commit-before-change files " before unstage")
(if (magit-no-commit-p)
(magit-run-git "rm" "--cached" "--" files)
(magit-run-git "reset" "HEAD" "--" files))
(magit-wip-commit-after-apply files " after unstage"))
;;;###autoload
(defun magit-unstage-all ()
"Remove all changes from the staging area."
(interactive)
(when (or (magit-anything-unstaged-p)
(magit-untracked-files))
(unless (magit-confirm 'unstage-all-changes)
(user-error "Abort")))
(magit-wip-commit-before-change nil " before unstage")
(magit-run-git "reset" "HEAD" "--")
(magit-wip-commit-after-apply nil " after unstage"))
;;;; Discard
(defun magit-discard ()
"Remove the change at point."
(interactive)
(--when-let (magit-apply--get-selection)
(pcase (list (magit-diff-type) (magit-diff-scope))
(`(committed ,_) (user-error "Cannot discard committed changes"))
(`(undefined ,_) (user-error "Cannot discard this change"))
(`(,_ region) (magit-discard-region it))
(`(,_ hunk) (magit-discard-hunk it))
(`(,_ hunks) (magit-discard-hunks it))
(`(,_ file) (magit-discard-file it))
(`(,_ files) (magit-discard-files it))
(`(,_ list) (magit-discard-files it)))))
(defun magit-discard-region (section)
(when (magit-confirm 'discard "Discard region")
(magit-discard-apply section 'magit-apply-region)))
(defun magit-discard-hunk (section)
(when (magit-confirm 'discard "Discard hunk")
(magit-discard-apply section 'magit-apply-hunk)))
(defun magit-discard-apply (section apply)
(if (eq (magit-diff-type section) 'unstaged)
(funcall apply section "--reverse")
(if (magit-anything-unstaged-p
nil (if (eq (magit-section-type section) 'file)
(magit-section-value section)
(magit-section-parent-value section)))
(progn (let ((inhibit-magit-refresh t))
(funcall apply section "--reverse" "--cached")
(funcall apply section "--reverse" "--reject"))
(magit-refresh))
(funcall apply section "--reverse" "--index"))))
(defun magit-discard-hunks (sections)
(when (magit-confirm 'discard
(format "Discard %s hunks from %s"
(length sections)
(magit-section-parent-value (car sections))))
(magit-discard-apply-n sections 'magit-apply-hunks)))
(defun magit-discard-apply-n (sections apply)
(let ((section (car sections)))
(if (eq (magit-diff-type section) 'unstaged)
(funcall apply sections "--reverse")
(if (magit-anything-unstaged-p
nil (if (eq (magit-section-type section) 'file)
(magit-section-value section)
(magit-section-parent-value section)))
(progn (let ((inhibit-magit-refresh t))
(funcall apply sections "--reverse" "--cached")
(funcall apply sections "--reverse" "--reject"))
(magit-refresh))
(funcall apply sections "--reverse" "--index")))))
(defun magit-discard-file (section)
(magit-discard-files (list section)))
(defun magit-discard-files (sections)
(let ((auto-revert-verbose nil)
(type (magit-diff-type (car sections)))
(status (magit-file-status))
files delete resurrect rename discard discard-new resolve)
(dolist (section sections)
(let ((file (magit-section-value section)))
(push file files)
(pcase (cons (pcase type
(`staged ?X)
(`unstaged ?Y)
(`untracked ?Z))
(cddr (assoc file status)))
(`(?Z) (--each (magit-untracked-files nil file)
(push it delete)))
((or `(?Z ?? ??) `(?Z ?! ?!)) (push file delete))
((or `(?Z ?D ? ) `(,_ ?D ?D)) (push file delete))
((or `(,_ ?U ,_) `(,_ ,_ ?U)) (push file resolve))
(`(,_ ?A ?A) (push file resolve))
(`(?X ?M ,(or ? ?M ?D)) (push section discard))
(`(?Y ,_ ?M ) (push section discard))
(`(?X ?A ?M ) (push file discard-new))
(`(?X ?C ?M ) (push file discard-new))
(`(?X ?A ,(or ? ?D)) (push file delete))
(`(?X ?C ,(or ? ?D)) (push file delete))
(`(?X ?D ,(or ? ?M )) (push file resurrect))
(`(?Y ,_ ?D ) (push file resurrect))
(`(?X ?R ,(or ? ?M ?D)) (push file rename)))))
(unwind-protect
(let ((inhibit-magit-refresh t))
(magit-wip-commit-before-change files " before discard")
(when resolve
(dolist (file (nreverse resolve))
(magit-checkout-stage file (magit-checkout-read-stage file))))
(magit-discard-files--resurrect (nreverse resurrect))
(magit-discard-files--delete (nreverse delete) status)
(magit-discard-files--rename (nreverse rename) status)
(magit-discard-files--discard (nreverse discard)
(nreverse discard-new))
(magit-wip-commit-after-apply files " after discard"))
(magit-refresh))))
(defun magit-discard-files--resurrect (files)
(when (magit-confirm-files 'resurrect files)
(if (eq (magit-diff-type) 'staged)
(magit-call-git "reset" "--" files)
(magit-call-git "checkout" "--" files))))
(defun magit-discard-files--delete (files status)
(when (if magit-delete-by-moving-to-trash
(magit-confirm-files 'trash files)
(magit-confirm-files 'delete files))
(let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
(dolist (file files)
(if (memq (magit-diff-type) '(unstaged untracked))
(progn (dired-delete-file file dired-recursive-deletes
magit-delete-by-moving-to-trash)
(dired-clean-up-after-deletion file))
(pcase (nth 3 (assoc file status))
(? (delete-file file t)
(magit-call-git "rm" "--cached" "--" file))
(?M (let ((temp (magit-git-string "checkout-index" "--temp" file)))
(string-match
(format "\\(.+?\\)\t%s" (regexp-quote file)) temp)
(rename-file (match-string 1 temp)
(setq temp (concat file ".~{index}~")))
(delete-file temp t))
(magit-call-git "rm" "--cached" "--force" "--" file))
(?D (magit-call-git "checkout" "--" file)
(delete-file file t)
(magit-call-git "rm" "--cached" "--force" "--" file))))))))
(defun magit-discard-files--rename (files status)
(when (magit-confirm 'rename "Undo rename %s" "Undo %i renames"
(mapcar (lambda (file)
(setq file (assoc file status))
(format "%s -> %s" (cadr file) (car file)))
files))
(dolist (file files)
(let ((orig (cadr (assoc file status))))
(if (file-exists-p file)
(progn
(--when-let (file-name-directory orig)
(make-directory it t))
(magit-call-git "mv" file orig))
(magit-call-git "rm" "--cached" "--" file)
(magit-call-git "reset" "--" orig))))))
(defun magit-discard-files--discard (sections new-files)
(let ((files (mapcar #'magit-section-value sections)))
(when (magit-confirm-files
'discard (append files new-files)
(format "Discard %s changes in" (magit-diff-type)))
(if (eq (magit-diff-type (car sections)) 'unstaged)
(magit-call-git "checkout" "--" files)
(when new-files
(magit-call-git "add" "--" new-files)
(magit-call-git "reset" "--" new-files))
(let ((binaries (magit-staged-binary-files)))
(when binaries
(setq sections
(--filter (not (member (magit-section-value it) binaries))
sections)))
(cond ((= (length sections) 1)
(magit-discard-apply (car sections) 'magit-apply-diff))
(sections
(magit-discard-apply-n sections 'magit-apply-diffs)))
(when binaries
(let ((modified (magit-unstaged-files t)))
(setq binaries (--separate (member it modified) binaries)))
(when (cadr binaries)
(magit-call-git "reset" "--" (cadr binaries)))
(when (car binaries)
(user-error
(concat
"Cannot discard staged changes to binary files, "
"which also have unstaged changes. Unstage instead.")))))))))
;;;; Reverse
(defun magit-reverse (&rest args)
"Reverse the change at point in the working tree.
With a prefix argument fallback to a 3-way merge. Doing
so causes the change to be applied to the index as well."
(interactive (and current-prefix-arg (list "--3way")))
(--when-let (magit-apply--get-selection)
(pcase (list (magit-diff-type) (magit-diff-scope))
(`(untracked ,_) (user-error "Cannot reverse untracked changes"))
(`(unstaged ,_) (user-error "Cannot reverse unstaged changes"))
(`(,_ region) (magit-reverse-region it args))
(`(,_ hunk) (magit-reverse-hunk it args))
(`(,_ hunks) (magit-reverse-hunks it args))
(`(,_ file) (magit-reverse-file it args))
(`(,_ files) (magit-reverse-files it args))
(`(,_ list) (magit-reverse-files it args)))))
(defun magit-reverse-region (section args)
(when (magit-confirm 'reverse "Reverse region")
(magit-reverse-apply section 'magit-apply-region args)))
(defun magit-reverse-hunk (section args)
(when (magit-confirm 'reverse "Reverse hunk")
(magit-reverse-apply section 'magit-apply-hunk args)))
(defun magit-reverse-hunks (sections args)
(when (magit-confirm 'reverse
(format "Reverse %s hunks from %s"
(length sections)
(magit-section-parent-value (car sections))))
(magit-reverse-apply sections 'magit-apply-hunks args)))
(defun magit-reverse-file (section args)
(magit-reverse-files (list section) args))
(defun magit-reverse-files (sections args)
(-let [(binaries sections)
(let ((bs (magit-staged-binary-files)))
(--separate (member (magit-section-value it) bs) sections))]
(when (magit-confirm-files 'reverse (mapcar #'magit-section-value sections))
(if (= (length sections) 1)
(magit-reverse-apply (car sections) 'magit-apply-diff args)
(magit-reverse-apply sections 'magit-apply-diffs args)))
(when binaries
(user-error "Cannot reverse binary files"))))
(defun magit-reverse-apply (section:s apply args)
(funcall apply section:s "--reverse" args
(and (not magit-reverse-atomically)
(not (member "--3way" args))
"--reject")))
(defun magit-reverse-in-index (&rest args)
"Reverse the change at point in the index but not the working tree.
Use this command to extract a change from `HEAD', while leaving
it in the working tree, so that it can later be committed using
a separate commit. A typical workflow would be:
0. Optionally make sure that there are no uncommitted changes.
1. Visit the `HEAD' commit and navigate to the change that should
not have been included in that commit.
2. Type \"u\" (`magit-unstage') to reverse it in the index.
This assumes that `magit-unstage-committed-changes' is non-nil.
3. Type \"c e\" to extend `HEAD' with the staged changes,
including those that were already staged before.
4. Optionally stage the remaining changes using \"s\" or \"S\"
and then type \"c c\" to create a new commit."
(interactive)
(magit-reverse (cons "--cached" args)))
(provide 'magit-apply)
;;; magit-apply.el ends here

File diff suppressed because it is too large Load Diff

View File

@ -1,262 +0,0 @@
;;; magit-autorevert.el --- revert buffers when files in repository change -*- lexical-binding: t -*-
;; Copyright (C) 2010-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Code:
(require 'cl-lib)
(require 'dash)
(require 'magit-git)
(require 'autorevert)
;;; Options
(defgroup magit-auto-revert nil
"Revert buffers when files in repository change."
:link '(custom-group-link auto-revert)
:link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers")
:group 'auto-revert
:group 'magit-essentials
:group 'magit-modes)
(defcustom auto-revert-buffer-list-filter nil
"Filter that determines which buffers `auto-revert-buffers' reverts.
This option is provided by `magit', which also redefines
`auto-revert-buffers' to respect it. Magit users who do not turn
on the local mode `auto-revert-mode' themselves, are best served
by setting the value to `magit-auto-revert-repository-buffers-p'.
However the default is nil, to not disturb users who do use the
local mode directly. If you experience delays when running Magit
commands, then you should consider using one of the predicates
provided by Magit - especially if you also use Tramp.
Users who do turn on `auto-revert-mode' in buffers in which Magit
doesn't do that for them, should likely not use any filter.
Users who turn on `global-auto-revert-mode', do not have to worry
about this option, because it is disregarded if the global mode
is enabled."
:package-version '(magit . "2.4.2")
:group 'auto-revert
:group 'magit-auto-revert
:group 'magit-related
:type '(radio (const :tag "no filter" nil)
(function-item magit-auto-revert-buffer-p)
(function-item magit-auto-revert-repository-buffer-p)
function))
(defcustom magit-auto-revert-tracked-only t
"Whether `magit-auto-revert-mode' only reverts tracked files."
:package-version '(magit . "2.4.0")
:group 'magit-auto-revert
:type 'boolean
:set (lambda (var val)
(set var val)
(when (and (bound-and-true-p magit-auto-revert-mode)
(featurep 'magit-autorevert))
(magit-auto-revert-mode -1)
(magit-auto-revert-mode))))
(defcustom magit-auto-revert-immediately t
"Whether Magit reverts buffers immediately.
If this is non-nil and either `global-auto-revert-mode' or
`magit-auto-revert-mode' is enabled, then Magit immediately
reverts buffers by explicitly calling `auto-revert-buffers'
after running git for side-effects.
If `auto-revert-use-notify' is non-nil (and file notifications
are actually supported), then `magit-auto-revert-immediately'
does not have to be non-nil, because the reverts happen
immediately anyway.
If `magit-auto-revert-immediately' and `auto-revert-use-notify'
are both nil, then reverts happen after `auto-revert-interval'
seconds of user inactivity. That is not desirable."
:package-version '(magit . "2.4.0")
:group 'magit-auto-revert
:type 'boolean)
;;; Mode
(defun magit-turn-on-auto-revert-mode-if-desired (&optional file)
(if file
(--when-let (find-buffer-visiting file)
(with-current-buffer it
(magit-turn-on-auto-revert-mode-if-desired)))
(when (and buffer-file-name
(file-readable-p buffer-file-name)
(magit-toplevel)
(or (not magit-auto-revert-tracked-only)
(magit-file-tracked-p buffer-file-name))
(not auto-revert-mode)) ; see #3014
(auto-revert-mode 1))))
;;;###autoload
(defvar magit-revert-buffers t) ; obsolete
;;;###autoload
(define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode
magit-turn-on-auto-revert-mode-if-desired
:package-version '(magit . "2.4.0")
:link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers")
:group 'magit-auto-revert
:group 'magit-essentials
;; When `global-auto-revert-mode' is enabled, then this mode is
;; redundant. When `magit-revert-buffers' is nil, then the user has
;; opted out of the automatic reverts while the old implementation
;; was still in use. In all other cases enable the mode because if
;; buffers are not automatically reverted that would make many very
;; common tasks much more cumbersome.
:init-value (and (with-no-warnings magit-revert-buffers)
(not global-auto-revert-mode)
(not noninteractive)))
;; - Unfortunately `:init-value t' only sets the value of the mode
;; variable but does not cause the mode function to be called.
;; - I don't think it works like this on purpose, but since one usually
;; should not enable global modes by default, it is understandable.
;; - If the user has set the variable `magit-auto-revert-mode' to nil
;; after loading magit (instead of doing so before loading magit or
;; by using the function), then we should still respect that setting.
;; - If the user has set the obsolete variable `magit-revert-buffers'
;; to nil before or after loading magit, then we should still respect
;; that setting.
;; - If the user sets one of these variables after loading magit and
;; after `after-init-hook' has run, then that won't have an effect
;; and there is nothing we can do about it.
(defun magit-auto-revert-mode--init-kludge ()
"This is an internal kludge to be used on `after-init-hook'.
Do not use this function elsewhere, and don't remove it from
the `after-init-hook'. For more information see the comments
and code surrounding the definition of this function."
;; `magit-revert-buffers' may have been set to nil before the alias
;; had been established, so consult the value of both variables.
(if (and magit-auto-revert-mode (with-no-warnings magit-revert-buffers))
(let ((start (current-time)))
(magit-message "Turning on magit-auto-revert-mode...")
(magit-auto-revert-mode 1)
(magit-message
"Turning on magit-auto-revert-mode...done%s"
(let ((elapsed (float-time (time-subtract (current-time) start))))
(if (> elapsed 0.2)
(format " (%.3fs, %s buffers checked)" elapsed
(length (buffer-list)))
""))))
(magit-auto-revert-mode -1)))
(if after-init-time
;; Since `after-init-hook' has already been
;; run, turn the mode on or off right now.
(magit-auto-revert-mode--init-kludge)
;; By the time the init file has been fully loaded the
;; values of the relevant variables might have changed.
(add-hook 'after-init-hook #'magit-auto-revert-mode--init-kludge t))
(put 'magit-auto-revert-mode 'function-documentation
"Toggle Magit Auto Revert mode.
With a prefix argument ARG, enable Magit Auto Revert mode if ARG
is positive, and disable it otherwise. If called from Lisp,
enable the mode if ARG is omitted or nil.
Magit Auto Revert mode is a global minor mode that reverts
buffers associated with a file that is located inside a Git
repository when the file changes on disk. Use `auto-revert-mode'
to revert a particular buffer. Or use `global-auto-revert-mode'
to revert all file-visiting buffers, not just those that visit
a file located inside a Git repository.
This global mode works by turning on the buffer-local mode
`auto-revert-mode' at the time a buffer is first created. The
local mode is turned on if the visited file is being tracked in
a Git repository at the time when the buffer is created.
If `magit-auto-revert-tracked-only' is non-nil (the default),
then only tracked files are reverted. But if you stage a
previously untracked file using `magit-stage', then this mode
notices that.
Unlike `global-auto-revert-mode', this mode never reverts any
buffers that are not visiting files.
The behavior of this mode can be customized using the options
in the `autorevert' and `magit-autorevert' groups.
This function calls the hook `magit-auto-revert-mode-hook'.")
(defun magit-auto-revert-buffers ()
(when (and magit-auto-revert-immediately
(or global-auto-revert-mode
(and magit-auto-revert-mode auto-revert-buffer-list)))
(let ((auto-revert-buffer-list-filter
(or auto-revert-buffer-list-filter
'magit-auto-revert-repository-buffer-p)))
(auto-revert-buffers))))
(defvar magit-auto-revert-toplevel nil)
(when (< emacs-major-version 25)
(defvar auto-revert-buffers-counter 1
"Incremented each time `auto-revert-buffers' is called"))
(defun magit-auto-revert-buffer-p (buffer)
"Return t if BUFFER visits a file inside the current repository.
The current repository is the one in which `default-directory' is
located. If there is no current repository, then return t for
any BUFFER."
(magit-auto-revert-repository-buffer-p buffer t))
(defun magit-auto-revert-repository-buffer-p (buffer &optional fallback)
"Return t if BUFFER visits a file inside the current repository.
The current repository is the one in which `default-directory' is
located. If there is no current repository, then return FALLBACK
\(which defaults to nil) for any BUFFER."
;; Call `magit-toplevel' just once per cycle.
(unless (and magit-auto-revert-toplevel
(= (cdr magit-auto-revert-toplevel)
auto-revert-buffers-counter))
(setq magit-auto-revert-toplevel
(cons (or (magit-toplevel) 'no-repo)
auto-revert-buffers-counter)))
(let ((top (car magit-auto-revert-toplevel)))
(if (eq top 'no-repo)
fallback
(let ((dir (with-current-buffer buffer default-directory)))
(and (equal (file-remote-p dir)
(file-remote-p top))
;; ^ `tramp-handle-file-in-directory-p' lacks this optimization.
(file-in-directory-p dir top))))))
(defun auto-revert-buffers--buffer-list-filter ()
(when (< emacs-major-version 25)
(cl-incf auto-revert-buffers-counter))
(when auto-revert-buffer-list-filter
(setq auto-revert-buffer-list
(--filter auto-revert-buffer-list-filter
auto-revert-buffer-list))))
(advice-add 'auto-revert-buffers :before
'auto-revert-buffers--buffer-list-filter)
(provide 'magit-autorevert)
;;; magit-autorevert.el ends here

View File

@ -1,210 +0,0 @@
;;; magit-bisect.el --- bisect support for Magit -*- lexical-binding: t -*-
;; Copyright (C) 2011-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; Use a binary search to find the commit that introduced a bug.
;;; Code:
(require 'magit)
;;; Options
(defcustom magit-bisect-show-graph t
"Whether to use `--graph' in the log showing commits yet to be bisected."
:package-version '(magit . "2.8.0")
:group 'magit-status
:type 'boolean)
(defface magit-bisect-good
'((t :foreground "DarkOliveGreen"))
"Face for good bisect revisions."
:group 'magit-faces)
(defface magit-bisect-skip
'((t :foreground "DarkGoldenrod"))
"Face for skipped bisect revisions."
:group 'magit-faces)
(defface magit-bisect-bad
'((t :foreground "IndianRed4"))
"Face for bad bisect revisions."
:group 'magit-faces)
;;; Commands
;;;###autoload (autoload 'magit-bisect-popup "magit-bisect" nil t)
(magit-define-popup magit-bisect-popup
"Popup console for bisect commands."
:man-page "git-bisect"
:actions '((?B "Start" magit-bisect-start)
(?s "Start script" magit-bisect-run))
:sequence-actions '((?b "Bad" magit-bisect-bad)
(?g "Good" magit-bisect-good)
(?k "Skip" magit-bisect-skip)
(?r "Reset" magit-bisect-reset)
(?s "Run script" magit-bisect-run))
:sequence-predicate 'magit-bisect-in-progress-p)
;;;###autoload
(defun magit-bisect-start (bad good)
"Start a bisect session.
Bisecting a bug means to find the commit that introduced it.
This command starts such a bisect session by asking for a know
good and a bad commit. To move the session forward use the
other actions from the bisect popup (\
\\<magit-status-mode-map>\\[magit-bisect-popup])."
(interactive (if (magit-bisect-in-progress-p)
(user-error "Already bisecting")
(magit-bisect-start-read-args)))
(magit-git-bisect "start" (list bad good) t))
(defun magit-bisect-start-read-args ()
(let ((b (magit-read-branch-or-commit "Start bisect with bad revision")))
(list b (magit-read-other-branch-or-commit "Good revision" b))))
;;;###autoload
(defun magit-bisect-reset ()
"After bisecting, cleanup bisection state and return to original `HEAD'."
(interactive)
(when (magit-confirm 'reset-bisect)
(magit-run-git "bisect" "reset")
(ignore-errors (delete-file (magit-git-dir "BISECT_CMD_OUTPUT")))))
;;;###autoload
(defun magit-bisect-good ()
"While bisecting, mark the current commit as good.
Use this after you have asserted that the commit does not contain
the bug in question."
(interactive)
(magit-git-bisect "good"))
;;;###autoload
(defun magit-bisect-bad ()
"While bisecting, mark the current commit as bad.
Use this after you have asserted that the commit does contain the
bug in question."
(interactive)
(magit-git-bisect "bad"))
;;;###autoload
(defun magit-bisect-skip ()
"While bisecting, skip the current commit.
Use this if for some reason the current commit is not a good one
to test. This command lets Git choose a different one."
(interactive)
(magit-git-bisect "skip"))
;;;###autoload
(defun magit-bisect-run (cmdline &optional bad good)
"Bisect automatically by running commands after each step.
Unlike `git bisect run' this can be used before bisecting has
begun. In that case it behaves like `git bisect start; git
bisect run'."
(interactive (let ((args (and (not (magit-bisect-in-progress-p))
(magit-bisect-start-read-args))))
(cons (read-shell-command "Bisect shell command: ") args)))
(when (and bad good)
(magit-bisect-start bad good))
(magit-git-bisect "run" (list shell-file-name shell-command-switch cmdline)))
(defun magit-git-bisect (subcommand &optional args no-assert)
(unless (or no-assert (magit-bisect-in-progress-p))
(user-error "Not bisecting"))
(magit-with-toplevel
(magit-run-git-with-logfile
(magit-git-dir "BISECT_CMD_OUTPUT") "bisect" subcommand args)))
;;; Sections
(defun magit-bisect-in-progress-p ()
(file-exists-p (magit-git-dir "BISECT_LOG")))
(defun magit-insert-bisect-output ()
"While bisecting, insert section with output from `git bisect'."
(when (magit-bisect-in-progress-p)
(let* ((lines
(or (magit-file-lines (magit-git-dir "BISECT_CMD_OUTPUT"))
(list "Bisecting: (no saved bisect output)"
"It appears you have invoked `git bisect' from a shell."
"There is nothing wrong with that, we just cannot display"
"anything useful here. Consult the shell output instead.")))
(done-re "^\\([a-z0-9]\\{40\\}\\) is the first bad commit$")
(bad-line (or (and (string-match done-re (car lines))
(pop lines))
(--first (string-match done-re it) lines))))
(magit-insert-section ((eval (if bad-line 'commit 'bisect-output))
(and bad-line (match-string 1 bad-line)))
(magit-insert-heading
(propertize (or bad-line (pop lines))
'face 'magit-section-heading))
(dolist (line lines)
(insert line "\n"))))
(insert "\n")))
(defun magit-insert-bisect-rest ()
"While bisecting, insert section visualizing the bisect state."
(when (magit-bisect-in-progress-p)
(magit-insert-section (bisect-view)
(magit-insert-heading "Bisect Rest:")
(magit-git-wash (apply-partially 'magit-log-wash-log 'bisect-vis)
"bisect" "visualize" "git" "log"
"--format=%h%d%x00%s" "--decorate=full"
(and magit-bisect-show-graph "--graph")))))
(defun magit-insert-bisect-log ()
"While bisecting, insert section logging bisect progress."
(when (magit-bisect-in-progress-p)
(magit-insert-section (bisect-log)
(magit-insert-heading "Bisect Log:")
(magit-git-wash #'magit-wash-bisect-log "bisect" "log")
(insert ?\n))))
(defun magit-wash-bisect-log (_args)
(let (beg)
(while (progn (setq beg (point-marker))
(re-search-forward "^\\(git bisect [^\n]+\n\\)" nil t))
(magit-bind-match-strings (heading) nil
(magit-delete-match)
(save-restriction
(narrow-to-region beg (point))
(goto-char (point-min))
(magit-insert-section (bisect-log heading t)
(insert (propertize heading 'face 'magit-section-secondary-heading))
(magit-insert-heading)
(magit-wash-sequence
(apply-partially 'magit-log-wash-rev 'bisect-log
(magit-abbrev-length)))
(insert ?\n)))))
(when (re-search-forward
"# first bad commit: \\[\\([a-z0-9]\\{40\\}\\)\\] [^\n]+\n" nil t)
(magit-bind-match-strings (hash) nil
(magit-delete-match)
(magit-insert-section (bisect-log)
(insert hash " is the first bad commit\n"))))))
(provide 'magit-bisect)
;;; magit-bisect.el ends here

View File

@ -1,570 +0,0 @@
;;; magit-blame.el --- blame support for Magit -*- lexical-binding: t -*-
;; Copyright (C) 2012-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; Annotates each line in file-visiting buffer with information from
;; the revision which last modified the line.
;;; Code:
(require 'magit)
;;; Options
(defgroup magit-blame nil
"Blame support for Magit."
:link '(info-link "(magit)Blaming")
:group 'magit-modes)
(defcustom magit-blame-heading-format "%-20a %C %s"
"Format string used for blame headings.
The following placeholders are recognized:
%H hash
%s summary
%a author
%A author time
%c committer
%C committer time
The author and committer time formats can be specified with
`magit-blame-time-format'."
:group 'magit-blame
:type 'string)
(defcustom magit-blame-time-format "%F %H:%M"
"Format for time strings in blame headings."
:group 'magit-blame
:type 'string)
(defcustom magit-blame-show-headings t
"Whether to initially show blame block headings.
The headings can also be toggled locally using command
`magit-blame-toggle-headings'."
:group 'magit-blame
:type 'boolean)
(defcustom magit-blame-disable-modes '(fci-mode yascroll-bar-mode)
"List of modes not compatible with Magit-Blame mode.
This modes are turned off when Magit-Blame mode is turned on,
and then turned on again when turning off the latter."
:group 'magit-blame
:type '(repeat (symbol :tag "Mode")))
(defcustom magit-blame-mode-lighter " Blame"
"The mode-line lighter of the Magit-Blame mode."
:group 'magit-blame
:type '(choice (const :tag "No lighter" "") string))
(defcustom magit-blame-goto-chunk-hook '(magit-blame-maybe-update-revision-buffer)
"Hook run by `magit-blame-next-chunk' and `magit-blame-previous-chunk'."
:package-version '(magit . "2.1.0")
:group 'magit-blame
:type 'hook
:get 'magit-hook-custom-get
:options '(magit-blame-maybe-update-revision-buffer))
(defface magit-blame-heading
'((((class color) (background light))
:background "grey80"
:foreground "black")
(((class color) (background dark))
:background "grey25"
:foreground "white"))
"Face for blame headings."
:group 'magit-faces)
(defface magit-blame-summary
'((t :inherit magit-blame-heading))
"Face for commit summary in blame headings."
:group 'magit-faces)
(defface magit-blame-hash
'((t :inherit magit-blame-heading))
"Face for commit hash in blame headings."
:group 'magit-faces)
(defface magit-blame-name
'((t :inherit magit-blame-heading))
"Face for author and committer names in blame headings."
:group 'magit-faces)
(defface magit-blame-date
'((t :inherit magit-blame-heading))
"Face for dates in blame headings."
:group 'magit-faces)
;;; Mode
(defvar magit-blame-mode-map
(let ((map (make-sparse-keymap)))
(cond ((featurep 'jkl)
(define-key map [return] 'magit-show-commit)
(define-key map (kbd "i") 'magit-blame-previous-chunk)
(define-key map (kbd "I") 'magit-blame-previous-chunk-same-commit)
(define-key map (kbd "k") 'magit-blame-next-chunk)
(define-key map (kbd "K") 'magit-blame-next-chunk-same-commit)
(define-key map (kbd "j") 'magit-blame)
(define-key map (kbd "l") 'magit-blame-reverse)
(define-key map (kbd "b") 'magit-blame-popup))
(t
(define-key map (kbd "C-m") 'magit-show-commit)
(define-key map (kbd "p") 'magit-blame-previous-chunk)
(define-key map (kbd "P") 'magit-blame-previous-chunk-same-commit)
(define-key map (kbd "n") 'magit-blame-next-chunk)
(define-key map (kbd "N") 'magit-blame-next-chunk-same-commit)
(define-key map (kbd "b") 'magit-blame)
(define-key map (kbd "f") 'magit-blame-reverse)
(define-key map (kbd "B") 'magit-blame-popup)))
(define-key map (kbd "t") 'magit-blame-toggle-headings)
(define-key map (kbd "q") 'magit-blame-quit)
(define-key map (kbd "M-w") 'magit-blame-copy-hash)
(define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up)
(define-key map (kbd "DEL") 'magit-diff-show-or-scroll-down)
map)
"Keymap for `magit-blame-mode'.")
(defun magit-blame-put-keymap-before-view-mode ()
"Put `magit-blame-mode' ahead of `view-mode' in `minor-mode-map-alist'."
(--when-let (assq 'magit-blame-mode
(cl-member 'view-mode minor-mode-map-alist :key #'car))
(setq minor-mode-map-alist
(cons it (delq it minor-mode-map-alist))))
(remove-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode))
(add-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode)
(defvar-local magit-blame-buffer-read-only nil)
(defvar-local magit-blame-cache nil)
(defvar-local magit-blame-disabled-modes nil)
(defvar-local magit-blame-process nil)
(defvar-local magit-blame-recursive-p nil)
(defvar-local magit-blame-reverse-p nil)
(defvar-local magit-blame-separator nil)
(define-minor-mode magit-blame-mode
"Display blame information inline.
\n\\{magit-blame-mode-map}"
:lighter magit-blame-mode-lighter
(cond (magit-blame-mode
(when (called-interactively-p 'any)
(setq magit-blame-mode nil)
(user-error
(concat "Don't call `magit-blame-mode' directly; "
"instead use `magit-blame' or `magit-blame-popup'")))
(setq magit-blame-buffer-read-only buffer-read-only)
(read-only-mode 1)
(dolist (mode magit-blame-disable-modes)
(when (and (boundp mode) (symbol-value mode))
(funcall mode -1)
(push mode magit-blame-disabled-modes)))
(setq magit-blame-separator (magit-blame-format-separator)))
(t
(unless magit-blame-buffer-read-only
(read-only-mode -1))
(dolist (mode magit-blame-disabled-modes)
(funcall mode 1))
(when (process-live-p magit-blame-process)
(kill-process magit-blame-process))
(save-excursion
(save-restriction
(widen)
(dolist (ov (overlays-in (point-min) (point-max)))
(when (overlay-get ov 'magit-blame)
(delete-overlay ov))))))))
(defun auto-revert-handler--unless-magit-blame-mode ()
"If Magit-Blame mode is on, then do nothing. See #1731."
magit-blame-mode)
(advice-add 'auto-revert-handler :before-until
'auto-revert-handler--unless-magit-blame-mode)
;;; Popup
;;;###autoload (autoload 'magit-blame-popup "magit-blame" nil t)
(magit-define-popup magit-blame-popup
"Popup console for blame commands."
:man-page "git-blame"
:switches '((?w "Ignore whitespace" "-w")
(?r "Do not treat root commits as boundaries" "--root"))
:options '((?M "Detect lines moved or copied within a file" "-M")
(?C "Detect lines moved or copied between files" "-C"))
:actions '((?b "Show blob touching these lines" magit-blame)
(?r (lambda ()
(with-current-buffer magit-pre-popup-buffer
(and (not buffer-file-name)
(propertize "Show last blob with these lines"
'face 'default))))
magit-blame-reverse))
:default-arguments '("-w")
:max-action-columns 1
:default-action 'magit-blame)
;;; Process
(defun magit-blame-arguments* (reverse)
(let ((args (magit-blame-arguments)))
(when (and reverse buffer-file-name)
(user-error "Only blob buffers can be blamed in reverse"))
(if (and magit-blame-mode
(or (and reverse magit-blame-reverse-p)
(and (not reverse)
(not magit-blame-reverse-p))))
(--if-let (magit-blame-chunk-get :previous-hash)
(list it (magit-blame-chunk-get :previous-file)
args (magit-blame-chunk-get :previous-start))
(user-error "Block has no further history"))
(--if-let (magit-file-relative-name nil (not magit-buffer-file-name))
(list (or magit-buffer-refname magit-buffer-revision) it args)
(if buffer-file-name
(user-error "Buffer isn't visiting a tracked file")
(user-error "Buffer isn't visiting a file"))))))
;;;###autoload
(defun magit-blame-reverse (revision file &optional args line)
"For each line show the last revision in which a line still existed.
\n(fn REVISION FILE &optional ARGS)" ; LINE is for internal use
(interactive (magit-blame-arguments* t))
(magit-blame revision file (cons "--reverse" args) line))
;;;###autoload
(defun magit-blame (revision file &optional args line)
"For each line show the revision that last touched it.
Interactively blame the file being visited in the current buffer.
If the buffer visits a revision of that file, then blame up to
that revision, otherwise blame the file's full history, including
uncommitted changes.
If Magit-Blame mode is already turned on then blame recursively, by
visiting REVISION:FILE (using `magit-find-file'), where revision
is the revision before the revision that added the lines at
point.
ARGS is a list of additional arguments to pass to `git blame';
only arguments available from `magit-blame-popup' should be used.
\n(fn REVISION FILE &optional ARGS)" ; LINE is for internal use
(interactive (magit-blame-arguments* nil))
(let ((toplevel (or (magit-toplevel)
(user-error "Not in git repository"))))
(let ((default-directory toplevel))
(if revision
(magit-find-file revision file)
(--if-let (find-buffer-visiting file)
(progn (switch-to-buffer it)
(save-buffer))
(find-file file))))
(let ((default-directory toplevel)
(reverse (and (member "--reverse" args) t)))
(widen)
(when line
(setq magit-blame-recursive-p t)
(goto-char (point-min))
(forward-line (1- line)))
(when (or (not magit-blame-mode)
(and reverse (not magit-blame-reverse-p))
(and (not reverse) magit-blame-reverse-p))
(setq magit-blame-reverse-p reverse)
(setq magit-blame-cache (make-hash-table :test 'equal))
(let ((show-headings magit-blame-show-headings))
(magit-blame-mode 1)
(setq-local magit-blame-show-headings show-headings))
(message "Blaming...")
(let ((magit-process-popup-time -1)
(inhibit-magit-refresh t))
(magit-run-git-async
"blame" "--incremental" args
"-L" (format "%s,%s"
(line-number-at-pos (window-start))
(line-number-at-pos (1- (window-end nil t))))
revision "--" file))
(setq magit-blame-process magit-this-process)
(set-process-filter magit-this-process 'magit-blame-process-filter)
(set-process-sentinel
magit-this-process
`(lambda (process event)
(when (memq (process-status process) '(exit signal))
(magit-process-sentinel process event)
(magit-blame-assert-buffer process)
(with-current-buffer (process-get process 'command-buf)
(when magit-blame-mode
(let ((magit-process-popup-time -1)
(inhibit-magit-refresh t)
(default-directory ,default-directory))
(magit-run-git-async "blame" "--incremental" ,@args
,revision "--" ,file))
(setq magit-blame-process magit-this-process)
(set-process-filter
magit-this-process 'magit-blame-process-filter)
(set-process-sentinel
magit-this-process 'magit-blame-process-sentinel))))))))))
(defun magit-blame-process-sentinel (process event)
(let ((status (process-status process)))
(when (memq status '(exit signal))
(magit-process-sentinel process event)
(if (and (eq status 'exit)
(zerop (process-exit-status process)))
(message "Blaming...done")
(magit-blame-assert-buffer process)
(with-current-buffer (process-get process 'command-buf)
(magit-blame-mode -1))
(message "Blaming...failed")))))
(defvar magit-blame-log nil
"Whether to log blame output to the process buffer.
This is intended for debugging purposes.")
(defun magit-blame-process-filter (process string)
(when magit-blame-log
(magit-process-filter process string))
(--when-let (process-get process 'partial-line)
(setq string (concat it string))
(setf (process-get process 'partial-line) nil))
(magit-blame-assert-buffer process)
(with-current-buffer (process-get process 'command-buf)
(when (and magit-blame-mode
(zerop (process-exit-status process)))
(let ((chunk (process-get process 'chunk))
(lines (split-string string "\n" t)))
(unless (string-match-p "\n\\'" string)
(process-put process 'chunk chunk)
(process-put process 'partial-line (car (last lines)))
(setq lines (butlast lines)))
(dolist (line lines)
(cond
((equal line ""))
((not chunk)
(string-match
"^\\(.\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)" line)
(setq chunk
(list :hash (let ((hash (match-string 1 line)))
(unless (equal hash (make-string 40 ?0))
hash))
:previous-start (string-to-number (match-string 2 line))
:start (string-to-number (match-string 3 line))
:lines (string-to-number (match-string 4 line)))))
((string-match "^filename \\(.+\\)" line)
(let* ((hash (plist-get chunk :hash))
(file (match-string 1 line)))
(--if-let (gethash hash magit-blame-cache)
(setq chunk (nconc chunk it))
(plist-put chunk :filename file)
(puthash hash chunk magit-blame-cache)))
(magit-blame-make-overlay chunk)
(setq chunk nil))
((string-match "^previous \\(.\\{40\\}\\) \\(.+\\)" line)
(plist-put chunk :previous-hash (match-string 1 line))
(plist-put chunk :previous-file (match-string 2 line)))
((string-match "^\\([^ ]+?-mail\\) <\\([^>]+\\)>" line)
(plist-put chunk (intern (concat ":" (match-string 1 line)))
(string-to-number (match-string 2 line))))
((string-match "^\\([^ ]+?-\\(?:time\\|tz\\)\\) \\(.+\\)" line)
(plist-put chunk (intern (concat ":" (match-string 1 line)))
(string-to-number (match-string 2 line))))
((string-match "^\\([^ ]+\\) \\(.+\\)" line)
(plist-put chunk (intern (concat ":" (match-string 1 line)))
(match-string 2 line))))
(process-put process 'chunk chunk))))))
(defun magit-blame-assert-buffer (process)
(unless (buffer-live-p (process-get process 'command-buf))
(kill-process process)
(user-error "Buffer being blamed has been killed")))
;;; Display
(defun magit-blame-make-overlay (chunk)
(let ((ov (save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(forward-line (1- (plist-get chunk :start)))
(--when-let (--first (overlay-get it 'magit-blame)
(overlays-at (point)))
(delete-overlay it))
(make-overlay (point)
(progn (forward-line
(plist-get chunk :lines))
(point))))))
(heading (magit-blame-format-heading chunk)))
(overlay-put ov 'magit-blame chunk)
(overlay-put ov 'magit-blame-heading heading)
(overlay-put ov 'before-string
(if magit-blame-show-headings
heading
magit-blame-separator))))
(defun magit-blame-format-separator ()
(propertize
(concat (propertize " " 'display '(space :height (2)))
(propertize "\n" 'line-height t))
'face (list :background (face-attribute 'magit-blame-heading :background))))
(defun magit-blame-format-heading (chunk)
(with-temp-buffer
(insert (format-spec
(concat magit-blame-heading-format "\n")
`((?H . ,(propertize (or (plist-get chunk :hash) "")
'face 'magit-blame-hash))
(?s . ,(propertize (or (plist-get chunk :summary) "")
'face 'magit-blame-summary))
(?a . ,(propertize (or (plist-get chunk :author) "")
'face 'magit-blame-name))
(?A . ,(propertize (magit-blame-format-time-string
magit-blame-time-format
(plist-get chunk :author-time)
(plist-get chunk :author-tz))
'face 'magit-blame-date))
(?c . ,(propertize (or (plist-get chunk :committer) "")
'face 'magit-blame-name))
(?C . ,(propertize (magit-blame-format-time-string
magit-blame-time-format
(plist-get chunk :committer-time)
(plist-get chunk :committer-tz))
'face 'magit-blame-date)))))
(goto-char (point-min))
(while (not (eobp))
(let ((face (get-text-property (point) 'face))
(next (or (next-single-property-change (point) 'face)
(point-max))))
(unless face
(put-text-property (point) next 'face 'magit-blame-heading))
(goto-char next)))
(buffer-string)))
(defun magit-blame-format-time-string (format time tz)
(format-time-string
format (seconds-to-time (+ time (* (/ tz 100) 60 60) (* (% tz 100) 60)))))
;;; Commands
(defun magit-blame-quit ()
"Turn off Magit-Blame mode.
If the buffer was created during a recursive blame,
then also kill the buffer."
(interactive)
(kill-local-variable 'magit-blame-reverse-p)
(if magit-blame-recursive-p
(kill-buffer)
(magit-blame-mode -1)))
(defun magit-blame-next-chunk ()
"Move to the next chunk."
(interactive)
(--if-let (next-single-char-property-change (point) 'magit-blame)
(progn (goto-char it)
(run-hooks 'magit-blame-goto-chunk-hook))
(user-error "No more chunks")))
(defun magit-blame-previous-chunk ()
"Move to the previous chunk."
(interactive)
(--if-let (previous-single-char-property-change (point) 'magit-blame)
(progn (goto-char it)
(run-hooks 'magit-blame-goto-chunk-hook))
(user-error "No more chunks")))
(defun magit-blame-next-chunk-same-commit (&optional previous)
"Move to the next chunk from the same commit.\n\n(fn)"
(interactive)
(-if-let (hash (magit-blame-chunk-get :hash))
(let ((pos (point)) ov)
(save-excursion
(while (and (not ov)
(not (= pos (if previous (point-min) (point-max))))
(setq pos (funcall
(if previous
'previous-single-char-property-change
'next-single-char-property-change)
pos 'magit-blame)))
(--when-let (magit-blame-overlay-at pos)
(when (equal (magit-blame-chunk-get :hash pos) hash)
(setq ov it)))))
(if ov
(goto-char (overlay-start ov))
(user-error "No more chunks from same commit")))
(user-error "This chunk hasn't been blamed yet")))
(defun magit-blame-previous-chunk-same-commit ()
"Move to the previous chunk from the same commit."
(interactive)
(magit-blame-next-chunk-same-commit 'previous-single-char-property-change))
(defun magit-blame-toggle-headings ()
"Show or hide blame chunk headings."
(interactive)
(setq-local magit-blame-show-headings (not magit-blame-show-headings))
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(while (not (eobp))
(let ((next (next-single-char-property-change (point) 'magit-blame)))
(--when-let (magit-blame-overlay-at (point))
(overlay-put it 'before-string
(if magit-blame-show-headings
(overlay-get it 'magit-blame-heading)
magit-blame-separator)))
(goto-char (or next (point-max))))))))
(defun magit-blame-copy-hash ()
"Save hash of the current chunk's commit to the kill ring.
When the region is active, then save the region's content
instead of the hash, like `kill-ring-save' would."
(interactive)
(if (use-region-p)
(copy-region-as-kill nil nil 'region)
(kill-new (message "%s" (magit-blame-chunk-get :hash)))))
;;; Utilities
(defun magit-blame-chunk-get (key &optional pos)
(--when-let (magit-blame-overlay-at pos)
(plist-get (overlay-get it 'magit-blame) key)))
(defun magit-blame-overlay-at (&optional pos)
(--first (overlay-get it 'magit-blame)
(overlays-at (or pos (point)))))
(defun magit-blame-maybe-update-revision-buffer ()
(unless magit--update-revision-buffer
(setq magit--update-revision-buffer nil)
(-when-let* ((commit (magit-blame-chunk-get :hash))
(buffer (magit-mode-get-buffer 'magit-revision-mode nil t)))
(setq magit--update-revision-buffer (list commit buffer))
(run-with-idle-timer
magit-update-other-window-delay nil
(lambda ()
(-let [(rev buf) magit--update-revision-buffer]
(setq magit--update-revision-buffer nil)
(when (buffer-live-p buf)
(let ((magit-display-buffer-noselect t))
(apply #'magit-show-commit rev (magit-diff-arguments))))))))))
(provide 'magit-blame)
;;; magit-blame.el ends here

View File

@ -1,364 +0,0 @@
;;; magit-bookmark.el --- bookmark support for Magit -*- lexical-binding: t -*-
;; Copyright (C) 2010-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Yuri Khan <yuri.v.khan@gmail.com>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; Support for bookmarks for most Magit buffers.
;;; Code:
(require 'magit)
(require 'bookmark)
;;; Supporting primitives
(defun magit-bookmark--jump (bookmark fn &rest args)
"Handle a Magit BOOKMARK.
This function will:
1. Bind `default-directory' to the repository root directory
stored in the `filename' bookmark property.
2. Invoke the function FN with ARGS as arguments. This needs to
restore the buffer.
3. Restore the expanded/collapsed status of top level sections
and the point position."
(declare (indent 2))
(let* ((default-directory (bookmark-get-filename bookmark)))
(if default-directory
(apply fn args)
(signal 'bookmark-error-no-filename (list 'stringp default-directory)))
(when (derived-mode-p 'magit-mode)
(-when-let (hidden-sections (bookmark-prop-get bookmark
'magit-hidden-sections))
(--each (magit-section-children magit-root-section)
(if (member (cons (magit-section-type it) (magit-section-value it))
hidden-sections)
(magit-section-hide it)
(magit-section-show it)))))
(--when-let (bookmark-get-position bookmark)
(goto-char it))
(--when-let (bookmark-get-front-context-string bookmark)
(when (search-forward it (point-max) t)
(goto-char (match-beginning 0))))
(--when-let (bookmark-get-rear-context-string bookmark)
(when (search-backward it (point-min) t)
(goto-char (match-end 0))))
nil))
(defun magit-bookmark--make-record (mode handler &optional make-props)
"Create a Magit bookmark.
MODE specifies the expected major mode of current buffer.
HANDLER should be a function that will be used to restore this
buffer.
MAKE-PROPS should be either nil or a function that will be called
with `magit-refresh-args' as the argument list, and may return an
alist whose every element has the form (PROP . VALUE) and
specifies additional properties to store in the bookmark."
(declare (indent 1))
(unless (eq major-mode mode)
(user-error "Not in a %s buffer" mode))
(let ((bookmark (bookmark-make-record-default 'no-file)))
(bookmark-prop-set bookmark 'handler handler)
(bookmark-set-filename bookmark (magit-toplevel))
(when (derived-mode-p 'magit-mode)
(bookmark-prop-set
bookmark 'magit-hidden-sections
(--map (cons (magit-section-type it) (magit-section-value it))
(-filter #'magit-section-hidden
(magit-section-children magit-root-section)))))
(when make-props
(pcase-dolist (`(,prop . ,value) (apply make-props magit-refresh-args))
(bookmark-prop-set bookmark prop value)))
bookmark))
;;; Status
;;;###autoload
(defun magit-bookmark--status-jump (bookmark)
"Handle a Magit status BOOKMARK."
(magit-bookmark--jump bookmark
(lambda () (magit-status-internal default-directory))))
;;;###autoload
(defun magit-bookmark--status-make-record ()
"Create a Magit status bookmark."
(magit-bookmark--make-record 'magit-status-mode
#'magit-bookmark--status-jump))
;;; Refs
;;;###autoload
(defun magit-bookmark--refs-jump (bookmark)
"Handle a Magit refs BOOKMARK."
(magit-bookmark--jump bookmark #'magit-show-refs
(bookmark-prop-get bookmark 'magit-refs)
(bookmark-prop-get bookmark 'magit-args)))
;;;###autoload
(defun magit-bookmark--refs-make-record ()
"Create a Magit refs bookmark."
(magit-bookmark--make-record 'magit-refs-mode
#'magit-bookmark--refs-jump
(lambda (refs args)
`((magit-refs . ,refs)
(magit-args . ,args)))))
;;; Log
;;;###autoload
(defun magit-bookmark--log-jump (bookmark)
"Handle a Magit log BOOKMARK."
(magit-bookmark--jump bookmark #'magit-log
(bookmark-prop-get bookmark 'magit-revs)
(bookmark-prop-get bookmark 'magit-args)
(bookmark-prop-get bookmark 'magit-files)))
(defun magit-bookmark--log-make-name (buffer-name revs _args files)
"Generate the default name for a log bookmark."
(concat
buffer-name " " (mapconcat #'identity revs " ")
(and files
(concat " touching " (mapconcat #'identity files " ")))))
;;;###autoload
(defun magit-bookmark--log-make-record ()
"Create a Magit log bookmark."
(magit-bookmark--make-record 'magit-log-mode
#'magit-bookmark--log-jump
(lambda (revs args files)
`((defaults . (,(magit-bookmark--log-make-name
(buffer-name) revs args files)))
(magit-revs . ,revs)
(magit-args . ,args)
(magit-files . ,files)))))
;;; Reflog
;;;###autoload
(defun magit-bookmark--reflog-jump (bookmark)
"Handle a Magit reflog BOOKMARK."
(magit-bookmark--jump bookmark
(lambda ()
(let ((magit-reflog-arguments (bookmark-prop-get bookmark 'magit-args)))
(magit-reflog (bookmark-prop-get bookmark 'magit-ref))))))
(defun magit-bookmark--reflog-make-name (buffer-name ref)
"Generate the default name for a reflog bookmark."
(concat buffer-name " " ref))
;;;###autoload
(defun magit-bookmark--reflog-make-record ()
"Create a Magit reflog bookmark."
(magit-bookmark--make-record 'magit-reflog-mode
#'magit-bookmark--reflog-jump
(lambda (ref args)
`((defaults . (,(magit-bookmark--reflog-make-name (buffer-name) ref)))
(magit-ref . ,ref)
(magit-args . ,args)))))
;;; Stashes
;;;###autoload
(defun magit-bookmark--stashes-jump (bookmark)
"Handle a Magit stash list BOOKMARK."
(magit-bookmark--jump bookmark #'magit-stash-list))
;;;###autoload
(defun magit-bookmark--stashes-make-record ()
"Create a Magit stash list bookmark."
(magit-bookmark--make-record 'magit-stashes-mode
#'magit-bookmark--stashes-jump))
;;; Cherry
;;;###autoload
(defun magit-bookmark--cherry-jump (bookmark)
"Handle a Magit cherry BOOKMARK."
(magit-bookmark--jump bookmark #'magit-cherry
(bookmark-prop-get bookmark 'magit-head)
(bookmark-prop-get bookmark 'magit-upstream)))
(defun magit-bookmark--cherry-make-name (buffer-name head upstream)
"Generate the default name for a cherry bookmark."
(concat buffer-name " " head " upstream " upstream))
;;;###autoload
(defun magit-bookmark--cherry-make-record ()
"Create a Magit cherry bookmark."
(magit-bookmark--make-record 'magit-cherry-mode
#'magit-bookmark--cherry-jump
(lambda (upstream head)
`((defaults . (,(magit-bookmark--cherry-make-name
(buffer-name) head upstream)))
(magit-head . ,head)
(magit-upstream . ,upstream)))))
;;; Diff
;;;###autoload
(defun magit-bookmark--diff-jump (bookmark)
"Handle a Magit diff BOOKMARK."
(magit-bookmark--jump bookmark #'magit-diff-setup
(bookmark-prop-get bookmark 'magit-rev-or-range)
(bookmark-prop-get bookmark 'magit-const)
(bookmark-prop-get bookmark 'magit-args)
(bookmark-prop-get bookmark 'magit-files)))
(defun magit-bookmark--resolve (rev-or-range)
"Return REV-OR-RANGE with ref names resolved to commit hashes."
(pcase (magit-git-lines "rev-parse" rev-or-range)
(`(,rev)
(magit-rev-abbrev rev))
((and `(,rev1 ,rev2)
(guard (/= ?^ (aref rev1 0)))
(guard (= ?^ (aref rev2 0))))
(concat (magit-rev-abbrev (substring rev2 1))
".."
(magit-rev-abbrev rev1)))
((and `(,rev1 ,rev2 ,rev3)
(guard (/= ?^ (aref rev1 0)))
(guard (/= ?^ (aref rev2 0)))
(guard (= ?^ (aref rev3 0))))
(ignore rev3)
(concat (magit-rev-abbrev rev1)
"..."
(magit-rev-abbrev rev2)))
(_
rev-or-range)))
(defun magit-bookmark--diff-make-name
(buffer-name rev-or-range const _args files)
"Generate a default name for a diff bookmark."
(if (member "--no-index" const)
(apply #'format "*magit-diff %s %s" files)
(concat buffer-name " "
(cond (rev-or-range)
((member "--cached" const) "staged")
(t "unstaged"))
(when files
(concat " in " (mapconcat #'identity files ", "))))))
;;;###autoload
(defun magit-bookmark--diff-make-record ()
"Create a Magit diff bookmark."
(magit-bookmark--make-record 'magit-diff-mode
#'magit-bookmark--diff-jump
(lambda (rev-or-range const args files)
(let ((resolved (magit-bookmark--resolve rev-or-range)))
`((defaults . (,(magit-bookmark--diff-make-name
(buffer-name) resolved const args files)))
(magit-rev-or-range . ,resolved)
(magit-const . ,const)
(magit-args . ,args)
(magit-files . ,files))))))
;;; Revision
;;;###autoload
(defun magit-bookmark--revision-jump (bookmark)
"Handle a Magit revision BOOKMARK."
(magit-bookmark--jump bookmark #'magit-show-commit
(bookmark-prop-get bookmark 'magit-rev)
(bookmark-prop-get bookmark 'args)
(bookmark-prop-get bookmark 'files)))
(defun magit-bookmark--revision-make-name (buffer-name rev _args files)
"Generate a default name for a revision bookmark."
(let ((subject (magit-rev-format "%s" rev)))
(concat buffer-name " "
(magit-rev-abbrev rev)
(cond (files (concat " " (mapconcat #'identity files " ")))
(subject (concat " " subject))))))
;;;###autoload
(defun magit-bookmark--revision-make-record ()
"Create a Magit revision bookmark."
;; magit-refresh-args stores the revision in relative form.
;; For bookmarks, the exact hash is more appropriate.
(magit-bookmark--make-record 'magit-revision-mode
#'magit-bookmark--revision-jump
(lambda (_rev _ args files)
`((defaults . (,(magit-bookmark--revision-make-name
(buffer-name) magit-buffer-revision-hash
args files)))
(magit-rev . ,magit-buffer-revision-hash)
(magit-args . ,args)
(magit-files . ,files)))))
;;; Stash
;;;###autoload
(defun magit-bookmark--stash-jump (bookmark)
"Handle a Magit stash BOOKMARK."
(magit-bookmark--jump bookmark #'magit-stash-show
(bookmark-prop-get bookmark 'magit-stash)
(bookmark-prop-get bookmark 'magit-args)
(bookmark-prop-get bookmark 'magit-files)))
(defun magit-bookmark--stash-make-name (buffer-name stash _args files)
"Generate the default name for a stash bookmark."
(concat buffer-name " " stash " "
(if files
(mapconcat #'identity files " ")
(magit-rev-format "%s" stash))))
;;;###autoload
(defun magit-bookmark--stash-make-record ()
"Create a Magit stash bookmark."
(magit-bookmark--make-record 'magit-stash-mode
#'magit-bookmark--stash-jump
(lambda (stash _ args files)
`((defaults . (,(magit-bookmark--stash-make-name
(buffer-name)
(magit-rev-abbrev magit-buffer-revision-hash)
args files)))
(magit-stash . ,magit-buffer-revision-hash)
(magit-args . ,args)
(magit-files . ,files)
(magit-hidden-sections
. ,(--map `(,(magit-section-type it)
. ,(replace-regexp-in-string (regexp-quote stash)
magit-buffer-revision-hash
(magit-section-value it)))
(-filter #'magit-section-hidden
(magit-section-children magit-root-section))))))))
;;; Submodules
;;;###autoload
(defun magit-bookmark--submodules-jump (bookmark)
"Handle a Magit submodule list BOOKMARK."
(magit-bookmark--jump bookmark #'magit-list-submodules))
;;;###autoload
(defun magit-bookmark--submodules-make-record ()
"Create a Magit submodule list bookmark."
(magit-bookmark--make-record 'magit-submodule-list-mode
#'magit-bookmark--submodules-jump))
(provide 'magit-bookmark)
;;; magit-bookmark.el ends here

View File

@ -1,971 +0,0 @@
;;; magit-branch.el --- branch support -*- lexical-binding: t -*-
;; Copyright (C) 2010-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; This library implements support for branches. It defines popups
;; and commands for creating, checking out, manipulating, and
;; configuring branches. Commands defined here are mainly concerned
;; with branches as pointers, commands that deal with what a branch
;; points at, are defined elsewhere.
;;; Code:
(require 'magit)
(require 'magit-collab)
;;; Options
(defcustom magit-branch-read-upstream-first t
"Whether to read upstream before name of new branch when creating a branch.
`nil' Read the branch name first.
`t' Read the upstream first.
`fallback' Read the upstream first, but if it turns out that the chosen
value is not a valid upstream (because it cannot be resolved
as an existing revision), then treat it as the name of the
new branch and continue by reading the upstream next."
:package-version '(magit . "2.2.0")
:group 'magit-commands
:type '(choice (const :tag "read branch name first" nil)
(const :tag "read upstream first" t)
(const :tag "read upstream first, with fallback" fallback)))
(defcustom magit-branch-prefer-remote-upstream nil
"Whether to favor remote upstreams when creating new branches.
When a new branch is created, then the branch, commit, or stash
at point is suggested as the default starting point of the new
branch, or if there is no such revision at point the current
branch. In either case the user may choose another starting
point.
If the chosen starting point is a branch, then it may also be set
as the upstream of the new branch, depending on the value of the
Git variable `branch.autoSetupMerge'. By default this is done
for remote branches, but not for local branches.
You might prefer to always use some remote branch as upstream.
If the chosen starting point is (1) a local branch, (2) whose
name matches a member of the value of this option, (3) the
upstream of that local branch is a remote branch with the same
name, and (4) that remote branch can be fast-forwarded to the
local branch, then the chosen branch is used as starting point,
but its own upstream is used as the upstream of the new branch.
Members of this option's value are treated as branch names that
have to match exactly unless they contain a character that makes
them invalid as a branch name. Recommended characters to use
to trigger interpretation as a regexp are \"*\" and \"^\". Some
other characters which you might expect to be invalid, actually
are not, e.g. \".+$\" are all perfectly valid. More precisely,
if `git check-ref-format --branch STRING' exits with a non-zero
status, then treat STRING as a regexp.
Assuming the chosen branch matches these conditions you would end
up with with e.g.:
feature --upstream--> origin/master
instead of
feature --upstream--> master --upstream--> origin/master
Which you prefer is a matter of personal preference. If you do
prefer the former, then you should add branches such as \"master\",
\"next\", and \"maint\" to the value of this options."
:package-version '(magit . "2.4.0")
:group 'magit-commands
:type '(repeat string))
(defcustom magit-branch-adjust-remote-upstream-alist nil
"Alist of upstreams to be used when branching from remote branches.
When creating a local branch from an ephemeral branch located
on a remote, e.g. a feature or hotfix branch, then that remote
branch should usually not be used as the upstream branch, since
the push-remote already allows accessing it and having both the
upstream and the push-remote reference the same related branch
would be wasteful. Instead a branch like \"maint\" or \"master\"
should be used as the upstream.
This option allows specifing the branch that should be used as
the upstream when branching certain remote branches. The value
is an alist of the form ((UPSTREAM . RULE)...). The first
matching element is used, the following elements are ignored.
UPSTREAM is the branch to be used as the upstream for branches
specified by RULE. It can be a local or a remote branch.
RULE can either be a regular expression, matching branches whose
upstream should be the one specified by UPSTREAM. Or it can be
a list of the only branches that should *not* use UPSTREAM; all
other branches will. Matching is done after stripping the remote
part of the name of the branch that is being branched from.
If you use a finite set of non-ephemeral branches across all your
repositories, then you might use something like:
((\"origin/master\" \"master\" \"next\" \"maint\"))
Or if the names of all your ephemeral branches contain a slash,
at least in some repositories, then a good value could be:
((\"origin/master\" . \"/\"))
Of course you can also fine-tune:
((\"origin/maint\" . \"\\`hotfix/\")
(\"origin/master\" . \"\\`feature/\"))
If you use remote branches as UPSTREAM, then you might also want
to set `magit-branch-prefer-remote-upstream' to a non-nil value.
However, I recommend that you use local branches as UPSTREAM."
:package-version '(magit . "2.9.0")
:group 'magit-commands
:type '(repeat (cons (string :tag "Use upstream")
(choice :tag "for branches"
(regexp :tag "matching")
(repeat :tag "except"
(string :tag "branch"))))))
(defcustom magit-branch-popup-show-variables t
"Whether the `magit-branch-popup' shows Git variables.
This defaults to t to avoid changing key bindings. When set to
nil, no variables are displayed directly in this popup, instead
the sub-popup `magit-branch-config-popup' has to be used to view
and change branch related variables."
:package-version '(magit . "2.7.0")
:group 'magit-commands
:type 'boolean)
;;; Branch Popup
(defvar magit-branch-config-variables)
;;;###autoload (autoload 'magit-branch-popup "magit" nil t)
(magit-define-popup magit-branch-popup
"Popup console for branch commands."
:man-page "git-branch"
:variables (lambda ()
(and magit-branch-popup-show-variables
magit-branch-config-variables))
:actions '((?b "Checkout" magit-checkout) nil
(?C "Configure..." magit-branch-config-popup)
(?l "Checkout local branch" magit-branch-checkout)
(?s "Create new spin-off" magit-branch-spinoff)
(?m "Rename" magit-branch-rename)
(?c "Checkout new branch" magit-branch-and-checkout)
(?n "Create new branch" magit-branch)
(?x "Reset" magit-branch-reset)
(?y "Checkout pull-request" magit-checkout-pull-request)
(?Y "Create from pull-request" magit-branch-pull-request)
(?k "Delete" magit-branch-delete)
(?w "Checkout new worktree" magit-worktree-checkout)
(?W "Create new worktree" magit-worktree-branch))
:default-action 'magit-checkout
:max-action-columns 3
:setup-function 'magit-branch-popup-setup)
(defun magit-branch-popup-setup (val def)
(magit-popup-default-setup val def)
(use-local-map (copy-keymap magit-popup-mode-map))
(dolist (ev (-filter #'magit-popup-event-p (magit-popup-get :variables)))
(local-set-key (vector (magit-popup-event-key ev))
'magit-invoke-popup-action)))
;;; Branch Commands
;;;###autoload
(defun magit-checkout (revision)
"Checkout REVISION, updating the index and the working tree.
If REVISION is a local branch, then that becomes the current
branch. If it is something else, then `HEAD' becomes detached.
Checkout fails if the working tree or the staging area contain
changes.
\n(git checkout REVISION)."
(interactive (list (magit-read-other-branch-or-commit "Checkout")))
(when (string-match "\\`heads/\\(.+\\)" revision)
(setq revision (match-string 1 revision)))
(magit-run-git "checkout" revision))
;;;###autoload
(defun magit-branch (branch start-point &optional args)
"Create BRANCH at branch or revision START-POINT.
\n(git branch [ARGS] BRANCH START-POINT)."
(interactive (magit-branch-read-args "Create branch"))
(magit-call-git "branch" args branch start-point)
(magit-branch-maybe-adjust-upstream branch start-point)
(magit-refresh))
;;;###autoload
(defun magit-branch-and-checkout (branch start-point &optional args)
"Create and checkout BRANCH at branch or revision START-POINT.
\n(git checkout [ARGS] -b BRANCH START-POINT)."
(interactive (magit-branch-read-args "Create and checkout branch"))
(if (string-match-p "^stash@{[0-9]+}$" start-point)
(magit-run-git "stash" "branch" branch start-point)
(magit-call-git "checkout" args "-b" branch start-point)
(magit-branch-maybe-adjust-upstream branch start-point)
(magit-refresh)))
;;;###autoload
(defun magit-branch-or-checkout (arg &optional start-point)
"Hybrid between `magit-checkout' and `magit-branch-and-checkout'.
Ask the user for an existing branch or revision. If the user
input actually can be resolved as a branch or revision, then
check that out, just like `magit-checkout' would.
Otherwise create and checkout a new branch using the input as
its name. Before doing so read the starting-point for the new
branch. This is similar to what `magit-branch-and-checkout'
does."
(interactive
(let ((arg (magit-read-other-branch-or-commit "Checkout")))
(list arg
(and (not (magit-rev-verify-commit arg))
(magit-read-starting-point "Create and checkout branch" arg)))))
(when (string-match "\\`heads/\\(.+\\)" arg)
(setq arg (match-string 1 arg)))
(if start-point
(magit-branch-and-checkout arg start-point (magit-branch-arguments))
(magit-checkout arg)))
;;;###autoload
(defun magit-branch-checkout (branch &optional start-point)
"Checkout an existing or new local branch.
Read a branch name from the user offering all local branches and
a subset of remote branches as candidates. Omit remote branches
for which a local branch by the same name exists from the list
of candidates. The user can also enter a completely new branch
name.
- If the user selects an existing local branch, then check that
out.
- If the user selects a remote branch, then create and checkout
a new local branch with the same name. Configure the selected
remote branch as push target.
- If the user enters a new branch name, then create and check
that out, after also reading the starting-point from the user.
In the latter two cases the upstream is also set. Whether it is
set to the chosen START-POINT or something else depends on the
value of `magit-branch-adjust-remote-upstream-alist', just like
when using `magit-branch-and-checkout'."
(interactive
(let* ((current (magit-get-current-branch))
(local (magit-list-local-branch-names))
(remote (--filter (and (string-match "[^/]+/" it)
(not (member (substring it (match-end 0))
(cons "HEAD" local))))
(magit-list-remote-branch-names)))
(choices (nconc (delete current local) remote))
(atpoint (magit-branch-at-point))
(choice (magit-completing-read
"Checkout branch" choices
nil nil nil 'magit-revision-history
(or (car (member atpoint choices))
(and atpoint
(car (member (and (string-match "[^/]+/" atpoint)
(substring atpoint (match-end 0)))
choices)))))))
(cond ((member choice remote)
(list (and (string-match "[^/]+/" choice)
(substring choice (match-end 0)))
choice))
((member choice local)
(list choice))
(t
(list choice (magit-read-starting-point "Create" choice))))))
(if (not start-point)
(magit-checkout branch)
(when (magit-anything-modified-p)
(user-error "Cannot checkout when there are uncommitted changes"))
(magit-branch-and-checkout branch start-point (magit-branch-arguments))
(when (magit-remote-branch-p start-point)
(pcase-let ((`(,remote . ,remote-branch)
(magit-split-branch-name start-point)))
(when (and (equal branch remote-branch)
(not (equal remote (magit-get "remote.pushDefault"))))
(magit-set remote "branch" branch "pushRemote"))))))
(defun magit-branch-maybe-adjust-upstream (branch start-point)
(--when-let
(or (and (magit-get-upstream-branch branch)
(magit-get-indirect-upstream-branch start-point))
(and (magit-remote-branch-p start-point)
(let ((name (cdr (magit-split-branch-name start-point))))
(car (--first (if (listp (cdr it))
(not (member name (cdr it)))
(string-match-p (cdr it) name))
magit-branch-adjust-remote-upstream-alist)))))
(magit-call-git "branch" (concat "--set-upstream-to=" it) branch)))
;;;###autoload
(defun magit-branch-orphan (branch start-point &optional args)
"Create and checkout an orphan BRANCH with contents from revision START-POINT.
\n(git checkout --orphan [ARGS] BRANCH START-POINT)."
(interactive (magit-branch-read-args "Create and checkout orphan branch"))
(magit-run-git "checkout" "--orphan" args branch start-point))
;;;###autoload
(defun magit-branch-pull-request (pr)
"Create and configure a new branch from a pull-request.
Please see the manual for more information."
(interactive (list (magit-read-pull-request "Branch pull request")))
(let-alist pr
(let* ((upstream (or (--first (magit--github-url-equal
(magit-get "remote" it "url")
.base.repo.ssh_url)
(magit-list-remotes))
(user-error
"Upstream repository %s not available as a remote"
.base.repo.ssh_url)))
(upstream-url (magit-get "remote" upstream "url"))
(remote .head.repo.owner.login)
(branch .head.ref)
(pr-branch branch))
(when (member branch (list .base.ref .base.default_branch))
(setq branch (format "pr-%s" .number)))
(when (magit-branch-p branch)
(user-error "Branch `%s' already exists" branch))
(if (equal .head.repo.full_name
.base.repo.full_name)
(let ((inhibit-magit-refresh t))
(magit-branch branch (concat upstream "/" pr-branch)))
(if (magit-remote-p remote)
(let ((url (magit-get "remote" remote "url"))
(fetch (magit-get-all "remote" remote "fetch")))
(unless (magit--github-url-equal url .head.repo.ssh_url)
(user-error
"Remote `%s' already exists but does not point to %s"
remote url))
(unless (member (format "+refs/heads/*:refs/remotes/%s/*" remote)
fetch)
(magit-call-git "remote" "set-branches"
"--add" remote pr-branch)
(magit-call-git "fetch" remote)))
(magit-call-git
"remote" "add" "-f" "--no-tags"
"-t" pr-branch remote
(cond ((or (string-prefix-p "git@" upstream-url)
(string-prefix-p "ssh://git@" upstream-url))
.head.repo.ssh_url)
((string-prefix-p "https://" upstream-url)
.head.repo.clone_url)
((string-prefix-p "git://" upstream-url)
.head.repo.git_url)
(t (error "%s has an unexpected format" upstream-url)))))
(magit-call-git "branch" branch
(concat remote "/" pr-branch))
(magit-call-git "branch" branch
(concat "--set-upstream-to="
(if magit-branch-prefer-remote-upstream
(concat upstream "/" .base.ref)
.base.ref)))
(magit-set "true" "branch" branch "rebase")
(if (or .locked (not (equal branch pr-branch)))
(magit-set upstream "branch" branch "pushRemote")
(magit-set remote "branch" branch "pushRemote"))
(magit-set remote "branch" branch "pullRequestRemote"))
(magit-set (number-to-string .number) "branch" branch "pullRequest")
(magit-set .title "branch" branch "description")
(magit-refresh)
branch)))
(defun magit-checkout-pull-request (pr)
"Create, configure and checkout a new branch from a pull-request.
Please see the manual for more information."
(interactive (list (magit-read-pull-request "Checkout pull request")))
(magit-checkout
(let ((inhibit-magit-refresh t))
(magit-branch-pull-request pr))))
(defun magit-branch-read-args (prompt)
(let ((args (magit-branch-arguments)))
(if magit-branch-read-upstream-first
(let ((choice (magit-read-starting-point prompt)))
(if (magit-rev-verify choice)
(list (magit-read-string-ns
(if magit-completing-read--silent-default
(format "%s (starting at `%s')" prompt choice)
"Name for new branch")
(let ((def (mapconcat #'identity
(cdr (split-string choice "/"))
"/")))
(and (member choice (magit-list-remote-branch-names))
(not (member def (magit-list-local-branch-names)))
def)))
choice args)
(if (eq magit-branch-read-upstream-first 'fallback)
(list choice (magit-read-starting-point prompt choice) args)
(user-error "Not a valid starting-point: %s" choice))))
(let ((branch (magit-read-string-ns (concat prompt " named"))))
(list branch
(with-no-warnings
(let ((magit-no-confirm-default nil))
(magit-read-starting-point prompt branch)))
args)))))
;;;###autoload
(defun magit-branch-spinoff (branch &optional from &rest args)
"Create new branch from the unpushed commits.
Create and checkout a new branch starting at and tracking the
current branch. That branch in turn is reset to the last commit
it shares with its upstream. If the current branch has no
upstream or no unpushed commits, then the new branch is created
anyway and the previously current branch is not touched.
This is useful to create a feature branch after work has already
began on the old branch (likely but not necessarily \"master\").
If the current branch is a member of the value of option
`magit-branch-prefer-remote-upstream' (which see), then the
current branch will be used as the starting point as usual, but
the upstream of the starting-point may be used as the upstream
of the new branch, instead of the starting-point itself.
If optional FROM is non-nil, then the source branch is reset
to `FROM~', instead of to the last commit it shares with its
upstream. Interactively, FROM is only ever non-nil, if the
region selects some commits, and among those commits, FROM is
the commit that is the fewest commits ahead of the source
branch.
The commit at the other end of the selection actually does not
matter, all commits between FROM and `HEAD' are moved to the new
branch. If FROM is not reachable from `HEAD' or is reachable
from the source branch's upstream, then an error is raised."
(interactive (list (magit-read-string-ns "Spin off branch")
(car (last (magit-region-values 'commit)))
(magit-branch-arguments)))
(when (magit-branch-p branch)
(user-error "Cannot spin off %s. It already exists" branch))
(-if-let (current (magit-get-current-branch))
(let ((tracked (magit-get-upstream-branch current))
base)
(when from
(unless (magit-rev-ancestor-p from current)
(user-error "Cannot spin off %s. %s is not reachable from %s"
branch from current))
(when (and tracked
(magit-rev-ancestor-p from tracked))
(user-error "Cannot spin off %s. %s is ancestor of upstream %s"
branch from tracked)))
(let ((magit-process-raise-error t))
(magit-call-git "checkout" args "-b" branch current))
(--when-let (magit-get-indirect-upstream-branch current)
(magit-call-git "branch" "--set-upstream-to" it branch))
(when (and tracked
(setq base
(if from
(concat from "^")
(magit-git-string "merge-base" current tracked)))
(not (magit-rev-eq base current)))
(magit-call-git "update-ref" "-m"
(format "reset: moving to %s" base)
(concat "refs/heads/" current) base))
(magit-refresh))
(magit-run-git "checkout" "-b" branch)))
;;;###autoload
(defun magit-branch-reset (branch to &optional args set-upstream)
"Reset a branch to the tip of another branch or any other commit.
When the branch being reset is the current branch, then do a
hard reset. If there are any uncommitted changes, then the user
has to confirm the reset because those changes would be lost.
This is useful when you have started work on a feature branch but
realize it's all crap and want to start over.
When resetting to another branch and a prefix argument is used,
then also set the target branch as the upstream of the branch
that is being reset."
(interactive
(let* ((atpoint (magit-local-branch-at-point))
(branch (magit-read-local-branch "Reset branch" atpoint)))
(list branch
(magit-completing-read (format "Reset %s to" branch)
(delete branch (magit-list-branch-names))
nil nil nil 'magit-revision-history
(or (and (not (equal branch atpoint)) atpoint)
(magit-get-upstream-branch branch)))
(magit-branch-arguments)
current-prefix-arg)))
(unless (member "--force" args)
(setq args (cons "--force" args)))
(if (equal branch (magit-get-current-branch))
(if (and (magit-anything-modified-p)
(not (yes-or-no-p "Uncommitted changes will be lost. Proceed? ")))
(user-error "Abort")
(magit-reset-hard to)
(when (and set-upstream (magit-branch-p to))
(magit-set-branch*merge/remote branch to)))
(magit-branch branch to args)))
;;;###autoload
(defun magit-branch-delete (branches &optional force)
"Delete one or multiple branches.
If the region marks multiple branches, then offer to delete
those, otherwise prompt for a single branch to be deleted,
defaulting to the branch at point."
;; One would expect this to be a command as simple as, for example,
;; `magit-branch-rename'; but it turns out everyone wants to squeeze
;; a bit of extra functionality into this one, including myself.
(interactive
(let ((branches (magit-region-values 'branch t))
(force current-prefix-arg))
(if (if (> (length branches) 1)
(magit-confirm t nil "Delete %i branches" branches)
(setq branches
(list (magit-read-branch-prefer-other
(if force "Force delete branch" "Delete branch")))))
(unless force
(--when-let (-remove #'magit-branch-merged-p branches)
(if (magit-confirm 'delete-unmerged-branch
"Delete unmerged branch %s"
"Delete %i unmerged branches" it)
(setq force branches)
(or (setq branches (-difference branches it))
(user-error "Abort")))))
(user-error "Abort"))
(list branches force)))
(let* ((refs (-map #'magit-ref-fullname branches))
(ambiguous (--filter (not it) refs)))
(when ambiguous
(user-error
"%s ambiguous. Please cleanup using git directly."
(let ((len (length ambiguous)))
(cond
((= len 1)
(format "%s is" (-first #'magit-ref-ambiguous-p branches)))
((= len (length refs))
(format "These %s names are" len))
(t
(format "%s of these names are" len))))))
(cond
((string-match "^refs/remotes/\\([^/]+\\)" (car refs))
(let* ((remote (match-string 1 (car refs)))
(offset (1+ (length remote))))
;; Assume the branches actually still exists on the remote.
(magit-run-git-async
"push" remote (--map (concat ":" (substring it offset)) branches))
;; If that is not the case, then this deletes the tracking branches.
(set-process-sentinel
magit-this-process
(apply-partially 'magit-delete-remote-branch-sentinel refs))))
((> (length branches) 1)
(setq branches (delete (magit-get-current-branch) branches))
(mapc 'magit-branch-maybe-delete-pr-remote branches)
(magit-run-git "branch" (if force "-D" "-d") branches))
(t ; And now for something completely different.
(let* ((branch (car branches))
(prompt (format "Branch %s is checked out. " branch)))
(when (equal branch (magit-get-current-branch))
(pcase (if (or (equal branch "master")
(not (magit-rev-verify "master")))
(magit-read-char-case prompt nil
(?d "[d]etach HEAD & delete" 'detach)
(?a "[a]bort" 'abort))
(magit-read-char-case prompt nil
(?d "[d]etach HEAD & delete" 'detach)
(?c "[c]heckout master & delete" 'master)
(?a "[a]bort" 'abort)))
(`detach (unless (or (equal force '(4))
(member branch force)
(magit-branch-merged-p branch t)
(magit-confirm 'delete-unmerged-branch
"Delete unmerged branch %s" ""
(list branch)))
(user-error "Abort"))
(magit-call-git "checkout" "--detach"))
(`master (unless (or (equal force '(4))
(member branch force)
(magit-branch-merged-p branch "master")
(magit-confirm 'delete-unmerged-branch
"Delete unmerged branch %s" ""
(list branch)))
(user-error "Abort"))
(magit-call-git "checkout" "master"))
(`abort (user-error "Abort")))
(setq force t))
(magit-branch-maybe-delete-pr-remote branch)
(magit-run-git "branch" (if force "-D" "-d") branch))))))
(put 'magit-branch-delete 'interactive-only t)
(defun magit-branch-maybe-delete-pr-remote (branch)
(-when-let (remote (magit-get "branch" branch "pullRequestRemote"))
(let* ((variable (format "remote.%s.fetch" remote))
(refspecs (magit-get-all variable)))
(unless (member (format "+refs/heads/*:refs/remotes/%s/*" remote)
refspecs)
(let ((refspec
(if (equal (magit-get "branch" branch "pushRemote") remote)
(format "+refs/heads/%s:refs/remotes/%s/%s"
branch remote branch)
(let ((merge (magit-get "branch" branch "merge")))
(and merge
(string-prefix-p "refs/heads/" merge)
(setq merge (substring merge 11))
(format "+refs/heads/%s:refs/remotes/%s/%s"
merge remote merge))))))
(when (member refspec refspecs)
(if (and (= (length refspecs) 1)
(magit-confirm 'delete-pr-remote
(format "Also delete remote %s (%s)" remote
"no pull-request branch remains")))
(magit-call-git "remote" "rm" remote)
(magit-call-git "config" "--unset" variable
(regexp-quote refspec)))))))))
(defun magit-delete-remote-branch-sentinel (refs process event)
(when (memq (process-status process) '(exit signal))
(if (= (process-exit-status process) 0)
(magit-process-sentinel process event)
(-if-let (rest (-filter #'magit-ref-exists-p refs))
(progn
(process-put process 'inhibit-refresh t)
(magit-process-sentinel process event)
(setq magit-this-error nil)
(message "Some remote branches no longer exist. %s"
"Deleting just the local tracking refs instead...")
(--each rest (magit-call-git "update-ref" "-d" it))
(magit-refresh)
(message "Deleting local remote-tracking refs...done"))
(magit-process-sentinel process event)))))
;;;###autoload
(defun magit-branch-rename (old new &optional force)
"Rename branch OLD to NEW.
With prefix, forces the rename even if NEW already exists.
\n(git branch -m|-M OLD NEW)."
(interactive
(let ((branch (magit-read-local-branch "Rename branch")))
(list branch
(magit-read-string-ns (format "Rename branch '%s' to" branch)
nil 'magit-revision-history)
current-prefix-arg)))
(when (string-match "\\`heads/\\(.+\\)" old)
(setq old (match-string 1 old)))
(unless (string= old new)
(magit-run-git "branch" (if force "-M" "-m") old new)))
;;; Config Popup
(defvar magit-branch-config-branch nil)
;;;###autoload
(defun magit-branch-config-popup (branch)
"Popup console for setting branch variables."
(interactive
(list (if (or current-prefix-arg
(and (eq magit-current-popup 'magit-branch-popup)
magit-branch-popup-show-variables))
(magit-read-local-branch "Configure branch")
(magit-get-current-branch))))
(let ((magit-branch-config-branch branch))
(magit-invoke-popup 'magit-branch-config-popup nil nil)))
(defvar magit-branch-config-variables
'((lambda ()
(concat
(propertize "Configure " 'face 'magit-popup-heading)
(propertize (magit-branch-config-branch) 'face 'magit-branch-local)))
(?d "branch.%s.description"
magit-edit-branch*description
magit-format-branch*description)
(?u "branch.%s.merge"
magit-set-branch*merge/remote
magit-format-branch*merge/remote)
(?r "branch.%s.rebase"
magit-cycle-branch*rebase
magit-format-branch*rebase)
(?p "branch.%s.pushRemote"
magit-cycle-branch*pushRemote
magit-format-branch*pushRemote)
"Configure repository defaults"
(?\M-r "pull.rebase"
magit-cycle-pull.rebase
magit-format-pull.rebase)
(?\M-p "remote.pushDefault"
magit-cycle-remote.pushDefault
magit-format-remote.pushDefault)
"Configure branch creation"
(?U "branch.autoSetupMerge"
magit-cycle-branch*autoSetupMerge
magit-format-branch*autoSetupMerge)
(?R "branch.autoSetupRebase"
magit-cycle-branch*autoSetupRebase
magit-format-branch*autoSetupRebase)))
(defvar magit-branch-config-popup
`(:man-page "git-branch"
:variables ,magit-branch-config-variables
:setup-function magit-branch-config-popup-setup))
(defun magit-branch-config-popup-setup (val def)
(magit-popup-default-setup val def)
(setq-local magit-branch-config-branch magit-branch-config-branch)
(use-local-map (copy-keymap magit-popup-mode-map))
(dolist (ev (-filter #'magit-popup-event-p (magit-popup-get :variables)))
(local-set-key (vector (magit-popup-event-key ev))
'magit-invoke-popup-action)))
(defun magit-branch-config-branch (&optional prompt)
(if prompt
(or (and (not current-prefix-arg)
(or magit-branch-config-branch
(magit-get-current-branch)))
(magit-read-local-branch prompt))
(or magit-branch-config-branch
(magit-get-current-branch)
"<name>")))
;;; Config Commands and Inserters
;;;###autoload
(defun magit-edit-branch*description (branch)
"Edit the description of the current branch.
With a prefix argument edit the description of another branch.
The description for the branch named NAME is stored in the Git
variable `branch.<name>.description'."
(interactive (list (magit-branch-config-branch "Edit branch description")))
(magit-run-git-with-editor "branch" "--edit-description" branch))
(defun magit-edit-branch*description-check-buffers ()
(and buffer-file-name
(string-match-p "/\\(BRANCH\\|EDIT\\)_DESCRIPTION\\'" buffer-file-name)
(add-hook 'with-editor-post-finish-hook
(lambda ()
(when (derived-mode-p 'magit-popup-mode)
(magit-refresh-popup-buffer)))
nil t)))
(add-hook 'find-file-hook 'magit-edit-branch*description-check-buffers)
(defun magit-format-branch*description ()
(let* ((branch (magit-branch-config-branch))
(width (+ (length branch) 19))
(var (format "branch.%s.description" branch)))
(concat var " " (make-string (- width (length var)) ?\s)
(-if-let (value (magit-get var))
(propertize value 'face 'magit-popup-option-value)
(propertize "unset" 'face 'magit-popup-disabled-argument)))))
;;;###autoload
(defun magit-set-branch*merge/remote (branch upstream)
"Set or unset the upstream of the current branch.
With a prefix argument do so for another branch.
When the branch in question already has an upstream then simply
unsets it. Invoke this command again to set another upstream.
Together the Git variables `branch.<name>.remote' and
`branch.<name>.merge' define the upstream branch of the local
branch named NAME. The value of `branch.<name>.remote' is the
name of the upstream remote. The value of `branch.<name>.merge'
is the full reference of the upstream branch, on the remote.
Non-interactively, when UPSTREAM is non-nil, then always set it
as the new upstream, regardless of whether another upstream was
already set. When nil, then always unset."
(interactive
(let ((branch (magit-branch-config-branch "Change upstream of branch")))
(list branch (and (not (magit-get-upstream-branch branch))
(magit-read-upstream-branch branch)))))
(if upstream
(-let (((remote . merge) (magit-split-branch-name upstream)))
(setf (magit-get (format "branch.%s.remote" branch)) remote)
(setf (magit-get (format "branch.%s.merge" branch))
(concat "refs/heads/" merge)))
(magit-call-git "branch" "--unset-upstream" branch))
(when (called-interactively-p 'any)
(magit-refresh)))
(defun magit-format-branch*merge/remote ()
(let* ((branch (magit-branch-config-branch))
(width (+ (length branch) 20))
(varM (format "branch.%s.merge" branch))
(varR (format "branch.%s.remote" branch))
(face (if (equal (magit-get varR) ".")
'magit-branch-local
'magit-branch-remote)))
(concat varM (make-string (- width (length varM)) ?\s)
(-if-let (value (magit-get varM))
(propertize value 'face face)
(propertize "unset" 'face 'magit-popup-disabled-argument))
"\n " varR (make-string (- width (length varR)) ?\s)
(-if-let (value (magit-get varR))
(propertize value 'face face)
(propertize "unset" 'face 'magit-popup-disabled-argument)))))
;;;###autoload
(defun magit-cycle-branch*rebase (branch)
"Cycle the value of `branch.<name>.rebase' for the current branch.
With a prefix argument cycle the value for another branch.
The Git variables `branch.<name>.rebase' controls whether pulling
into the branch named NAME is done by rebasing that branch onto
the fetched branch or by merging that branch.
When `true' then pulling is done by rebasing.
When `false' then pulling is done by merging.
When that variable is undefined then the value of `pull.rebase'
is used instead. It defaults to `false'."
(interactive (list (magit-branch-config-branch
"Cycle branch.<name>.rebase for")))
(magit--set-popup-variable (format "branch.%s.rebase" branch)
'("true" "false")
"false" "pull.rebase"))
(defun magit-format-branch*rebase ()
(let ((branch (magit-branch-config-branch)))
(magit--format-popup-variable:choices
(format "branch.%s.rebase" branch)
'("true" "false")
"false" "pull.rebase"
(+ (length branch) 20))))
;;;###autoload
(defun magit-cycle-branch*pushRemote (branch)
"Cycle the value of `branch.<name>.pushRemote' for the current branch.
With a prefix argument cycle the value for another branch.
The Git variable `branch.<name>.pushRemote' specifies the remote
that the branch named NAME is usually pushed to. The value has
to be the name of an existing remote.
If that variable is undefined, then the value of the Git variable
`remote.pushDefault' is used instead, provided that it is defined,
which by default it is not."
(interactive (list (magit-branch-config-branch
"Cycle branch.<name>.pushRemote for")))
(magit--set-popup-variable (format "branch.%s.pushRemote" branch)
(magit-list-remotes)
"remote.pushDefault"))
(defun magit-format-branch*pushRemote ()
(let ((branch (magit-branch-config-branch)))
(magit--format-popup-variable:choices
(format "branch.%s.pushRemote" branch)
(magit-list-remotes)
nil "remote.pushDefault"
(+ (length branch) 20))))
;;;###autoload
(defun magit-cycle-pull.rebase ()
"Cycle the repository-local value of `pull.rebase'.
The Git variable `pull.rebase' specifies whether pulling is done
by rebasing or by merging. It can be overwritten using the Git
variable `branch.<name>.rebase'.
When `true' then pulling is done by rebasing.
When `false' (the default) then pulling is done by merging."
(interactive)
(magit--set-popup-variable "pull.rebase" '("true" "false") "false"))
(defun magit-format-pull.rebase ()
(magit--format-popup-variable:choices
"pull.rebase" '("true" "false") "false" nil 19))
;;;###autoload
(defun magit-cycle-remote.pushDefault ()
"Cycle the repository-local value of `remote.pushDefault'.
The Git variable `remote.pushDefault' specifies the remote that
local branches are usually pushed to. It can be overwritten
using the Git variable `branch.<name>.pushRemote'."
(interactive)
(magit--set-popup-variable "remote.pushDefault" (magit-list-remotes)))
(defun magit-format-remote.pushDefault ()
(magit--format-popup-variable:choices
"remote.pushDefault" (magit-list-remotes) nil nil 19))
;;;###autoload
(defun magit-cycle-branch*autoSetupMerge ()
"Cycle the repository-local value of `branch.autoSetupMerge'.
The Git variable `branch.autoSetupMerge' under what circumstances
creating a branch (named NAME) should result in the variables
`branch.<name>.merge' and `branch.<name>.remote' being set
according to the starting point used to create the branch. If
the starting point isn't a branch, then these variables are never
set.
When `always' then the variables are set regardless of whether
the starting point is a local or a remote branch.
When `true' (the default) then the variable are set when the
starting point is a remote branch, but not when it is a local
branch.
When `false' then the variables are never set."
(interactive)
(magit--set-popup-variable "branch.autoSetupMerge"
'("always" "true" "false") "true"))
(defun magit-format-branch*autoSetupMerge ()
(magit--format-popup-variable:choices
"branch.autoSetupMerge" '("always" "true" "false") "true" nil 23))
;;;###autoload
(defun magit-cycle-branch*autoSetupRebase ()
"Cycle the repository-local value of `branch.autoSetupRebase'.
The Git variable `branch.autoSetupRebase' specifies whether
creating a branch (named NAME) should result in the variable
`branch.<name>.rebase' being set to `true'.
When `always' then the variable is set regardless of whether the
starting point is a local or a remote branch.
When `local' then the variable are set when the starting point
is a local branch, but not when it is a remote branch.
When `remote' then the variable are set when the starting point
is a remote branch, but not when it is a local branch.
When `never' (the default) then the variable is never set."
(interactive)
(magit--set-popup-variable "branch.autoSetupRebase"
'("always" "local" "remote" "never") "never"))
(defun magit-format-branch*autoSetupRebase ()
(magit--format-popup-variable:choices
"branch.autoSetupRebase"
'("always" "local" "remote" "never")
"never" nil 23))
(provide 'magit-branch)
;;; magit-branch.el ends here

View File

@ -1,131 +0,0 @@
;;; magit-collab.el --- collaboration tools -*- lexical-binding: t -*-
;; Copyright (C) 2010-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; This library implements various collaboration tools. These tools
;; are only early incarnation -- implementing collaboration tools is
;; a top priority for future development.
;; Currently these tools (including `magit-branch-pull-request', which
;; is defined elsewhere) only support Github, but support for other
;; Git forges as well as mailing list based collaboration is in
;; planning.
;;; Code:
(require 'magit)
(require 'ghub)
;;; Variables
(defvar magit-github-token-scopes '(repo)
"The Github API scopes needed by Magit.
`repo' is the only required scope. Without this scope none of
Magit's features that use the API work. Instead of this scope
you could use `public_repo' if you are only interested in public
repositories.
`repo' Grants read/write access to code, commit statuses,
invitations, collaborators, adding team memberships, and
deployment statuses for public and private repositories
and organizations.
`public_repo' Grants read/write access to code, commit statuses,
collaborators, and deployment statuses for public repositories
and organizations. Also required for starring public
repositories.")
;;; Commands
;;;###autoload
(defun magit-browse-pull-request (pr)
"Visit pull-request PR using `browse-url'.
Currently this only supports Github, but that restriction will
be lifted eventually to support other Git forges."
(interactive (list (magit-read-pull-request "Visit pull request")))
(browse-url (format "https://github.com/%s/pull/%s"
;; Cannot use --> yet. See #3134.
(let* ((it pr)
(it (cdr (assq 'base it)))
(it (cdr (assq 'repo it)))
(it (cdr (assq 'full_name it))))
it)
(cdr (assq 'number pr)))))
;;; Utilities
(defun magit-read-pull-request (prompt)
"Read a pull request from the user, prompting with PROMPT.
Return the Git forge's API response. Currently this function
only supports Github, but that will change eventually."
(let* ((origin (magit-upstream-repository))
(url (magit-get "remote" origin "url"))
(prs (ghub-get
(format "/repos/%s/pulls"
(and (string-match
"github.com[:/]\\(.+?\\)\\(?:\\.git\\)?\\'" url)
(match-string 1 url)))
nil :auth 'magit))
(choice (magit-completing-read
prompt
(--map (format "%s %s"
(cdr (assq 'number it))
(cdr (assq 'title it)))
prs)
nil t))
(number (and (string-match "\\([0-9]+\\)" choice)
(string-to-number (match-string 1 choice)))))
(--first (eq (cdr (assq 'number it)) number) prs)))
(defun magit-upstream-repository ()
"Return the remote name of the upstream repository.
If the Git variable `magit.upstream' is set, then return its
value. Otherwise return \"origin\". If the remote does not
exist, then raise an error."
(let ((remote (or (magit-get "magit.upstream") "origin")))
(unless (magit-remote-p remote)
(error "No remote named `%s' exists (consider setting `magit.upstream')"
remote))
(unless (string-match-p "github\\.com" (magit-get "remote" remote "url"))
(error "Currently only Github is supported"))
remote))
(defconst magit--github-url-regexp "\
\\`\\(?:git://\\|git@\\|ssh://git@\\|https://\\)github.com[/:]\
\\(\\([^/]+\\)/\\(.+?\\)\\)\
\\(?:\\.git\\)?\\'")
(defun magit--github-url-equal (r1 r2)
(or (equal r1 r2)
(let ((n1 (and (string-match magit--github-url-regexp r1)
(match-string 1 r1)))
(n2 (and (string-match magit--github-url-regexp r2)
(match-string 1 r2))))
(and n1 n2 (equal n1 n2)))))
(provide 'magit-collab)
;;; magit-collab.el ends here

View File

@ -1,449 +0,0 @@
;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*-
;; Copyright (C) 2008-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; This library implements commands for creating Git commits. These
;; commands just initiate the commit, support for writing the commit
;; messages is implemented in `git-commit.el'.
;;; Code:
(require 'magit)
(require 'magit-sequence)
(eval-when-compile (require 'epa)) ; for `epa-protocol'
(eval-when-compile (require 'epg))
(declare-function epg-sub-key-id 'epg)
(declare-function epg-key-sub-key-list 'epg)
(declare-function epg-key-user-id-list 'epg)
(declare-function epg-user-id-string 'epg)
(declare-function epg-decode-dn 'epg)
(declare-function epg-list-keys 'epg)
;;; Options
(defcustom magit-commit-arguments nil
"The arguments used when committing."
:group 'magit-git-arguments
:type '(repeat (string :tag "Argument")))
(defcustom magit-commit-ask-to-stage 'verbose
"Whether to ask to stage everything when committing and nothing is staged."
:package-version '(magit . "2.3.0")
:group 'magit-commands
:type '(choice (const :tag "Ask showing diff" verbose)
(const :tag "Ask" t)
(const :tag "Don't ask" nil)))
(defcustom magit-commit-show-diff t
"Whether the relevant diff is automatically shown when committing."
:package-version '(magit . "2.3.0")
:group 'magit-commands
:type 'boolean)
(defcustom magit-commit-extend-override-date t
"Whether using `magit-commit-extend' changes the committer date."
:package-version '(magit . "2.3.0")
:group 'magit-commands
:type 'boolean)
(defcustom magit-commit-reword-override-date t
"Whether using `magit-commit-reword' changes the committer date."
:package-version '(magit . "2.3.0")
:group 'magit-commands
:type 'boolean)
(defcustom magit-commit-squash-confirm t
"Whether the commit targeted by squash and fixup has to be confirmed.
When non-nil then the commit at point (if any) is used as default
choice, otherwise it has to be confirmed. This option only
affects `magit-commit-squash' and `magit-commit-fixup'. The
\"instant\" variants always require confirmation because making
an error while using those is harder to recover from."
:package-version '(magit . "2.1.0")
:group 'magit-commands
:type 'boolean)
;;; Popup
(defun magit-commit-popup (&optional arg)
"Popup console for commit commands."
(interactive "P")
(--if-let (magit-commit-message-buffer)
(switch-to-buffer it)
(magit-invoke-popup 'magit-commit-popup nil arg)))
(defvar magit-commit-popup
'(:variable magit-commit-arguments
:man-page "git-commit"
:switches ((?a "Stage all modified and deleted files" "--all")
(?e "Allow empty commit" "--allow-empty")
(?v "Show diff of changes to be committed" "--verbose")
(?h "Disable hooks" "--no-verify")
(?s "Add Signed-off-by line" "--signoff")
(?R "Claim authorship and reset author date" "--reset-author"))
:options ((?A "Override the author" "--author=")
(?S "Sign using gpg" "--gpg-sign=" magit-read-gpg-secret-key)
(?C "Reuse commit message" "--reuse-message="
magit-read-reuse-message))
:actions ((?c "Commit" magit-commit)
(?e "Extend" magit-commit-extend)
(?f "Fixup" magit-commit-fixup)
(?F "Instant Fixup" magit-commit-instant-fixup) nil
(?w "Reword" magit-commit-reword)
(?s "Squash" magit-commit-squash)
(?S "Instant Squash" magit-commit-instant-squash) nil
(?a "Amend" magit-commit-amend)
(?A "Augment" magit-commit-augment))
:max-action-columns 4
:default-action magit-commit))
(magit-define-popup-keys-deferred 'magit-commit-popup)
(defun magit-commit-arguments nil
(if (eq magit-current-popup 'magit-commit-popup)
magit-current-popup-args
magit-commit-arguments))
(defvar magit-gpg-secret-key-hist nil)
(defun magit-read-gpg-secret-key (prompt &optional _initial-input)
(require 'epa)
(let ((keys (--map (concat (epg-sub-key-id (car (epg-key-sub-key-list it)))
" "
(-when-let (id-obj (car (epg-key-user-id-list it)))
(let ((id-str (epg-user-id-string id-obj)))
(if (stringp id-str)
id-str
(epg-decode-dn id-obj)))))
(epg-list-keys (epg-make-context epa-protocol) nil t))))
(car (split-string (magit-completing-read
prompt keys nil nil nil 'magit-gpg-secret-key-hist
(car (or magit-gpg-secret-key-hist keys)))
" "))))
(defun magit-read-reuse-message (prompt &optional default)
(magit-completing-read prompt (magit-list-refnames)
nil nil nil 'magit-revision-history
(or default
(and (magit-rev-verify "ORIG_HEAD")
"ORIG_HEAD"))))
;;; Commands
;;;###autoload
(defun magit-commit (&optional args)
"Create a new commit on `HEAD'.
With a prefix argument, amend to the commit at `HEAD' instead.
\n(git commit [--amend] ARGS)"
(interactive (if current-prefix-arg
(list (cons "--amend" (magit-commit-arguments)))
(list (magit-commit-arguments))))
(when (member "--all" args)
(setq this-command 'magit-commit-all))
(when (setq args (magit-commit-assert args))
(let ((default-directory (magit-toplevel)))
(magit-run-git-with-editor "commit" args))))
;;;###autoload
(defun magit-commit-amend (&optional args)
"Amend the last commit.
\n(git commit --amend ARGS)"
(interactive (list (magit-commit-arguments)))
(magit-run-git-with-editor "commit" "--amend" args))
;;;###autoload
(defun magit-commit-extend (&optional args override-date)
"Amend the last commit, without editing the message.
With a prefix argument keep the committer date, otherwise change
it. The option `magit-commit-extend-override-date' can be used
to inverse the meaning of the prefix argument. \n(git commit
--amend --no-edit)"
(interactive (list (magit-commit-arguments)
(if current-prefix-arg
(not magit-commit-extend-override-date)
magit-commit-extend-override-date)))
(when (setq args (magit-commit-assert args (not override-date)))
(let ((process-environment process-environment))
(unless override-date
(push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
(magit-run-git-with-editor "commit" "--amend" "--no-edit" args))))
;;;###autoload
(defun magit-commit-reword (&optional args override-date)
"Reword the last commit, ignoring staged changes.
With a prefix argument keep the committer date, otherwise change
it. The option `magit-commit-reword-override-date' can be used
to inverse the meaning of the prefix argument.
Non-interactively respect the optional OVERRIDE-DATE argument
and ignore the option.
\n(git commit --amend --only)"
(interactive (list (magit-commit-arguments)
(if current-prefix-arg
(not magit-commit-reword-override-date)
magit-commit-reword-override-date)))
(let ((process-environment process-environment))
(unless override-date
(push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
(magit-run-git-with-editor "commit" "--amend" "--only" args)))
;;;###autoload
(defun magit-commit-fixup (&optional commit args)
"Create a fixup commit.
With a prefix argument the target COMMIT has to be confirmed.
Otherwise the commit at point may be used without confirmation
depending on the value of option `magit-commit-squash-confirm'."
(interactive (list (magit-commit-at-point)
(magit-commit-arguments)))
(magit-commit-squash-internal "--fixup" commit args))
;;;###autoload
(defun magit-commit-squash (&optional commit args)
"Create a squash commit, without editing the squash message.
With a prefix argument the target COMMIT has to be confirmed.
Otherwise the commit at point may be used without confirmation
depending on the value of option `magit-commit-squash-confirm'."
(interactive (list (magit-commit-at-point)
(magit-commit-arguments)))
(magit-commit-squash-internal "--squash" commit args))
;;;###autoload
(defun magit-commit-augment (&optional commit args)
"Create a squash commit, editing the squash message.
With a prefix argument the target COMMIT has to be confirmed.
Otherwise the commit at point may be used without confirmation
depending on the value of option `magit-commit-squash-confirm'."
(interactive (list (magit-commit-at-point)
(magit-commit-arguments)))
(magit-commit-squash-internal "--squash" commit args nil t))
;;;###autoload
(defun magit-commit-instant-fixup (&optional commit args)
"Create a fixup commit targeting COMMIT and instantly rebase."
(interactive (list (magit-commit-at-point)
(magit-commit-arguments)))
(magit-commit-squash-internal "--fixup" commit args t))
;;;###autoload
(defun magit-commit-instant-squash (&optional commit args)
"Create a squash commit targeting COMMIT and instantly rebase."
(interactive (list (magit-commit-at-point)
(magit-commit-arguments)))
(magit-commit-squash-internal "--squash" commit args t))
(defun magit-commit-squash-internal
(option commit &optional args rebase edit confirmed)
(-when-let (args (magit-commit-assert args t))
(when commit
(when (and rebase (not (magit-rev-ancestor-p commit "HEAD")))
(magit-read-char-case
(format "%s isn't an ancestor of HEAD. " commit) nil
(?c "[c]reate without rebasing" (setq rebase nil))
(?s "[s]elect other" (setq commit nil))
(?a "[a]bort" (user-error "Quit")))))
(when commit
(setq commit (magit-rebase-interactive-assert commit)))
(if (and commit
(or confirmed
(not (or rebase
current-prefix-arg
magit-commit-squash-confirm))))
(let ((magit-commit-show-diff nil))
(push (concat option "=" commit) args)
(unless edit
(push "--no-edit" args))
(if rebase
(magit-with-editor
(magit-call-git
"commit" "--no-gpg-sign"
(-remove-first
(apply-partially #'string-match-p "\\`--gpg-sign=")
args)))
(magit-run-git-with-editor "commit" args))
t) ; The commit was created; used by below lambda.
(magit-log-select
(lambda (commit)
(when (and (magit-commit-squash-internal option commit args
rebase edit t)
rebase)
(magit-rebase-interactive-1 commit
(list "--autosquash" "--autostash")
"" "true" t)))
(format "Type %%p on a commit to %s into it,"
(substring option 2))
nil nil (list "--graph"))
(when magit-commit-show-diff
(let ((magit-display-buffer-noselect t))
(apply #'magit-diff-staged nil (magit-diff-arguments)))))))
(defun magit-commit-assert (args &optional strict)
(cond
((or (magit-anything-staged-p)
(and (magit-anything-unstaged-p)
;; ^ Everything of nothing is still nothing.
(member "--all" args))
(and (not strict)
;; ^ For amend variants that don't make sense otherwise.
(or (member "--amend" args)
(member "--allow-empty" args))))
(or args (list "--")))
((and (magit-rebase-in-progress-p)
(not (magit-anything-unstaged-p))
(y-or-n-p "Nothing staged. Continue in-progress rebase? "))
(magit-run-git-sequencer "rebase" "--continue")
nil)
((and (file-exists-p (magit-git-dir "MERGE_MSG"))
(not (magit-anything-unstaged-p)))
(or args (list "--")))
((not (magit-anything-unstaged-p))
(user-error "Nothing staged (or unstaged)"))
(magit-commit-ask-to-stage
(when (eq magit-commit-ask-to-stage 'verbose)
(magit-diff-unstaged))
(prog1 (when (y-or-n-p "Nothing staged. Stage and commit everything? ")
(magit-run-git "add" "-u" ".")
(or args (list "--")))
(when (and (eq magit-commit-ask-to-stage 'verbose)
(derived-mode-p 'magit-diff-mode))
(magit-mode-bury-buffer))))
(t
(user-error "Nothing staged"))))
;;; Pending Diff
(defun magit-commit-diff ()
(when (and git-commit-mode magit-commit-show-diff)
(-when-let (diff-buffer (magit-mode-get-buffer 'magit-diff-mode))
;; This window just started displaying the commit message
;; buffer. Without this that buffer would immediately be
;; replaced with the diff buffer. See #2632.
(unrecord-window-buffer nil diff-buffer))
(condition-case nil
(let ((args (car (magit-diff-arguments)))
(magit-inhibit-save-previous-winconf 'unset)
(magit-display-buffer-noselect t)
(inhibit-quit nil))
(message "Diffing changes to be committed (C-g to abort diffing)")
(-if-let (fn (cl-case last-command
(magit-commit
(apply-partially 'magit-diff-staged nil))
(magit-commit-all
(apply-partially 'magit-diff-working-tree nil))
((magit-commit-amend
magit-commit-reword
magit-rebase-reword-commit)
'magit-diff-while-amending)))
(funcall fn args)
(if (magit-anything-staged-p)
(magit-diff-staged nil args)
(magit-diff-while-amending args))))
(quit))))
;; Mention `magit-diff-while-committing' because that's
;; always what I search for when I try to find this line.
(add-hook 'server-switch-hook 'magit-commit-diff)
(add-to-list 'with-editor-server-window-alist
(cons git-commit-filename-regexp 'switch-to-buffer))
;;; Message Utilities
(defun magit-commit-message-buffer ()
(let* ((find-file-visit-truename t) ; git uses truename of COMMIT_EDITMSG
(topdir (magit-toplevel)))
(--first (equal topdir (with-current-buffer it
(and git-commit-mode (magit-toplevel))))
(append (buffer-list (selected-frame))
(buffer-list)))))
(defvar magit-commit-add-log-insert-function 'magit-commit-add-log-insert
"Used by `magit-commit-add-log' to insert a single entry.")
(defun magit-commit-add-log ()
"Add a stub for the current change into the commit message buffer.
If no commit is in progress, then initiate it. Use the function
specified by variable `magit-commit-add-log-insert-function' to
actually insert the entry."
(interactive)
(let ((hunk (magit-section-when 'hunk it))
(log (magit-commit-message-buffer)) buf pos)
(save-window-excursion
(call-interactively #'magit-diff-visit-file)
(setq buf (current-buffer))
(setq pos (point)))
(unless log
(unless (magit-commit-assert nil)
(user-error "Abort"))
(magit-commit)
(while (not (setq log (magit-commit-message-buffer)))
(sit-for 0.01)))
(save-excursion
(with-current-buffer buf
(goto-char pos)
(funcall magit-commit-add-log-insert-function log
(magit-file-relative-name)
(and hunk (add-log-current-defun)))))))
(defun magit-commit-add-log-insert (buffer file defun)
(with-current-buffer buffer
(undo-boundary)
(goto-char (point-max))
(while (re-search-backward (concat "^" comment-start) nil t))
(cond ((re-search-backward (format "* %s\\(?: (\\([^)]+\\))\\)?: " file)
nil t)
(when (equal (match-string 1) defun)
(setq defun nil))
(re-search-forward ": "))
(t
(when (re-search-backward "^[\\*(].+\n" nil t)
(goto-char (match-end 0)))
(while (re-search-forward "^[^\\*#\n].*\n" nil t))
(if defun
(progn (insert (format "* %s (%s): \n" file defun))
(setq defun nil))
(insert (format "* %s: \n" file)))
(backward-char)
(unless (looking-at "\n[\n\\']")
(insert ?\n)
(backward-char))))
(when defun
(forward-line)
(let ((limit (save-excursion
(and (re-search-forward "^\\*" nil t)
(point)))))
(unless (or (looking-back (format "(%s): " defun)
(line-beginning-position))
(re-search-forward (format "^(%s): " defun) limit t))
(while (re-search-forward "^[^\\*#\n].*\n" limit t))
(insert (format "(%s): \n" defun))
(backward-char))))))
(provide 'magit-commit)
;;; magit-commit.el ends here

View File

@ -1,132 +0,0 @@
;;; magit-core.el --- core functionality -*- lexical-binding: t -*-
;; Copyright (C) 2010-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; This library requires several other libraries, so that yet other
;; libraries can just require this one, instead of having to require
;; all the other ones. In other words this separates the low-level
;; stuff from the rest. It also defines some Custom groups.
;;; Code:
(require 'magit-popup)
(require 'magit-utils)
(require 'magit-section)
(require 'magit-git)
(require 'magit-mode)
(require 'magit-margin)
(require 'magit-process)
(require 'magit-autorevert)
(defgroup magit nil
"Controlling Git from Emacs."
:link '(url-link "https://magit.vc")
:link '(info-link "(magit)FAQ")
:link '(info-link "(magit)")
:group 'tools)
(defgroup magit-essentials nil
"Options that every Magit user should briefly think about.
Each of these options falls into one or more of these categories:
* Options that affect Magit's behavior in fundamental ways.
* Options that affect safety.
* Options that affect performance.
* Options that are of a personal nature."
:link '(info-link "(magit)Essential Settings")
:group 'magit)
(defgroup magit-miscellaneous nil
"Miscellanous Magit options."
:group 'magit)
(defgroup magit-commands nil
"Options controlling behavior of certain commands."
:group 'magit)
(defgroup magit-git-arguments nil
"Options controlling what arguments are passed to Git.
Most of these options can be set using the respective popup,
and it is recommended that you do that because then you can
be certain that Magit supports the arguments that you select.
An option `magit-NAME-argument' specifies the arguments that
are enabled by default by the popup `magit-NAME-popup'."
:link '(info-link "(magit-popup)Customizing Existing Popups")
:link '(info-link "(magit-popup)Usage")
:group 'magit-commands)
(defgroup magit-modes nil
"Modes used or provided by Magit."
:group 'magit)
(defgroup magit-buffers nil
"Options concerning Magit buffers."
:link '(info-link "(magit)Modes and Buffers")
:group 'magit)
(defgroup magit-refresh nil
"Options controlling how Magit buffers are refreshed."
:link '(info-link "(magit)Automatic Refreshing of Magit Buffers")
:group 'magit
:group 'magit-buffers)
(defgroup magit-faces nil
"Faces used by Magit."
:group 'magit
:group 'faces)
(defgroup magit-extensions nil
"Extensions to Magit."
:group 'magit)
(custom-add-to-group 'magit-modes 'magit-popup 'custom-group)
(custom-add-to-group 'magit-faces 'magit-popup-faces 'custom-group)
(custom-add-to-group 'magit-modes 'git-commit 'custom-group)
(custom-add-to-group 'magit-faces 'git-commit-faces 'custom-group)
(custom-add-to-group 'magit-modes 'git-rebase 'custom-group)
(custom-add-to-group 'magit-faces 'git-rebase-faces 'custom-group)
(custom-add-to-group 'magit-process 'with-editor 'custom-group)
(defgroup magit-related nil
"Options that are relevant to Magit but that are defined elsewhere."
:link '(custom-group-link vc)
:link '(custom-group-link smerge)
:link '(custom-group-link ediff)
:link '(custom-group-link auto-revert)
:group 'magit
:group 'magit-extensions
:group 'magit-essentials)
(custom-add-to-group 'magit-related 'auto-revert-check-vc-info 'custom-variable)
(custom-add-to-group 'magit-auto-revert 'auto-revert-check-vc-info 'custom-variable)
(custom-add-to-group 'magit-related 'ediff-window-setup-function 'custom-variable)
(custom-add-to-group 'magit-related 'smerge-refine-ignore-whitespace 'custom-variable)
(custom-add-to-group 'magit-related 'vc-follow-symlinks 'custom-variable)
(provide 'magit-core)
;;; magit-core.el ends here

File diff suppressed because it is too large Load Diff

View File

@ -1,507 +0,0 @@
;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding: t -*-
;; Copyright (C) 2010-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; This library provides basic support for Ediff.
;;; Code:
(require 'magit)
(require 'ediff)
(require 'smerge-mode)
(defvar smerge-ediff-buf)
(defvar smerge-ediff-windows)
;;; Options
(defgroup magit-ediff nil
"Ediff support for Magit."
:link '(info-link "(magit)Ediffing")
:group 'magit-extensions)
(defcustom magit-ediff-quit-hook
'(magit-ediff-cleanup-auxiliary-buffers
magit-ediff-restore-previous-winconf)
"Hooks to run after finishing Ediff, when that was invoked using Magit.
The hooks are run in the Ediff control buffer. This is similar
to `ediff-quit-hook' but takes the needs of Magit into account.
The `ediff-quit-hook' is ignored by Ediff sessions which were
invoked using Magit."
:package-version '(magit . "2.2.0")
:group 'magit-ediff
:type 'hook
:get 'magit-hook-custom-get
:options '(magit-ediff-cleanup-auxiliary-buffers
magit-ediff-restore-previous-winconf))
(defcustom magit-ediff-dwim-show-on-hunks nil
"Whether `magit-ediff-dwim' runs show variants on hunks.
If non-nil, `magit-ediff-show-staged' or
`magit-ediff-show-unstaged' are called based on what section the
hunk is in. Otherwise, `magit-ediff-dwim' runs
`magit-ediff-stage' when point is on an uncommitted hunk."
:package-version '(magit . "2.2.0")
:group 'magit-ediff
:type 'boolean)
(defcustom magit-ediff-show-stash-with-index t
"Whether `magit-ediff-show-stash' shows the state of the index.
If non-nil, use a third Ediff buffer to distinguish which changes
in the stash were staged. In cases where the stash contains no
staged changes, fall back to a two-buffer Ediff.
More specifically, a stash is a merge commit, stash@{N}, with
potentially three parents.
* stash@{N}^1 represents the `HEAD' commit at the time the stash
was created.
* stash@{N}^2 records any changes that were staged when the stash
was made.
* stash@{N}^3, if it exists, contains files that were untracked
when stashing.
If this option is non-nil, `magit-ediff-show-stash' will run
Ediff on a file using three buffers: one for stash@{N}, another
for stash@{N}^1, and a third for stash@{N}^2.
Otherwise, Ediff uses two buffers, comparing
stash@{N}^1..stash@{N}. Along with any unstaged changes, changes
in the index commit, stash@{N}^2, will be shown in this
comparison unless they conflicted with changes in the working
tree at the time of stashing."
:package-version '(magit . "2.6.0")
:group 'magit-ediff
:type 'boolean)
;;; Commands
(defvar magit-ediff-previous-winconf nil)
;;;###autoload (autoload 'magit-ediff-popup "magit-ediff" nil t)
(magit-define-popup magit-ediff-popup
"Popup console for ediff commands."
:actions '((?E "Dwim" magit-ediff-dwim)
(?u "Show unstaged" magit-ediff-show-unstaged)
(?s "Stage" magit-ediff-stage)
(?i "Show staged" magit-ediff-show-staged)
(?m "Resolve" magit-ediff-resolve)
(?w "Show worktree" magit-ediff-show-working-tree)
(?r "Diff range" magit-ediff-compare)
(?c "Show commit" magit-ediff-show-commit) nil
(?z "Show stash" magit-ediff-show-stash))
:max-action-columns 2)
;;;###autoload
(defun magit-ediff-resolve (file)
"Resolve outstanding conflicts in FILE using Ediff.
FILE has to be relative to the top directory of the repository.
In the rare event that you want to manually resolve all
conflicts, including those already resolved by Git, use
`ediff-merge-revisions-with-ancestor'."
(interactive
(let ((current (magit-current-file))
(unmerged (magit-unmerged-files)))
(unless unmerged
(user-error "There are no unresolved conflicts"))
(list (magit-completing-read "Resolve file" unmerged nil t nil nil
(car (member current unmerged))))))
(magit-with-toplevel
(with-current-buffer (find-file-noselect file)
(smerge-ediff)
(setq-local
ediff-quit-hook
(lambda ()
(let ((bufC ediff-buffer-C)
(bufS smerge-ediff-buf))
(with-current-buffer bufS
(when (yes-or-no-p (format "Conflict resolution finished; save %s? "
buffer-file-name))
(erase-buffer)
(insert-buffer-substring bufC)
(save-buffer))))
(when (buffer-live-p ediff-buffer-A) (kill-buffer ediff-buffer-A))
(when (buffer-live-p ediff-buffer-B) (kill-buffer ediff-buffer-B))
(when (buffer-live-p ediff-buffer-C) (kill-buffer ediff-buffer-C))
(when (buffer-live-p ediff-ancestor-buffer)
(kill-buffer ediff-ancestor-buffer))
(let ((magit-ediff-previous-winconf smerge-ediff-windows))
(run-hooks 'magit-ediff-quit-hook)))))))
;;;###autoload
(defun magit-ediff-stage (file)
"Stage and unstage changes to FILE using Ediff.
FILE has to be relative to the top directory of the repository."
(interactive
(list (magit-completing-read "Selectively stage file"
(magit-tracked-files) nil nil nil nil
(magit-current-file))))
(magit-with-toplevel
(let* ((conf (current-window-configuration))
(bufA (magit-get-revision-buffer "HEAD" file))
(bufB (get-buffer (concat file ".~{index}~")))
(bufBrw (and bufB (with-current-buffer bufB (not buffer-read-only))))
(bufC (get-file-buffer file))
(fileBufC (or bufC (find-file-noselect file)))
(coding-system-for-read
(with-current-buffer fileBufC buffer-file-coding-system)))
(ediff-buffers3
(or bufA (magit-find-file-noselect "HEAD" file))
(with-current-buffer (magit-find-file-index-noselect file t)
(setq buffer-read-only nil)
(current-buffer))
fileBufC
`((lambda ()
(setq-local
ediff-quit-hook
(lambda ()
(and (buffer-live-p ediff-buffer-B)
(buffer-modified-p ediff-buffer-B)
(with-current-buffer ediff-buffer-B
(magit-update-index)))
(and (buffer-live-p ediff-buffer-C)
(buffer-modified-p ediff-buffer-C)
(with-current-buffer ediff-buffer-C
(when (y-or-n-p
(format "Save file %s? " buffer-file-name))
(save-buffer))))
,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
,@(if bufB
(unless bufBrw '((with-current-buffer ediff-buffer-B
(setq buffer-read-only t))))
'((ediff-kill-buffer-carefully ediff-buffer-B)))
,@(unless bufC '((ediff-kill-buffer-carefully ediff-buffer-C)))
(let ((magit-ediff-previous-winconf ,conf))
(run-hooks 'magit-ediff-quit-hook))))))
'ediff-buffers3))))
;;;###autoload
(defun magit-ediff-compare (revA revB fileA fileB)
"Compare REVA:FILEA with REVB:FILEB using Ediff.
FILEA and FILEB have to be relative to the top directory of the
repository. If REVA or REVB is nil, then this stands for the
working tree state.
If the region is active, use the revisions on the first and last
line of the region. With a prefix argument, instead of diffing
the revisions, choose a revision to view changes along, starting
at the common ancestor of both revisions (i.e., use a \"...\"
range)."
(interactive (-let [(revA revB) (magit-ediff-compare--read-revisions
nil current-prefix-arg)]
(nconc (list revA revB)
(magit-ediff-read-files revA revB))))
(magit-with-toplevel
(let ((conf (current-window-configuration))
(bufA (if revA
(magit-get-revision-buffer revA fileA)
(get-file-buffer fileA)))
(bufB (if revB
(magit-get-revision-buffer revB fileB)
(get-file-buffer fileB))))
(ediff-buffers
(or bufA (if revA
(magit-find-file-noselect revA fileA)
(find-file-noselect fileA)))
(or bufB (if revB
(magit-find-file-noselect revB fileB)
(find-file-noselect fileB)))
`((lambda ()
(setq-local
ediff-quit-hook
(lambda ()
,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
(let ((magit-ediff-previous-winconf ,conf))
(run-hooks 'magit-ediff-quit-hook))))))
'ediff-revision))))
(defun magit-ediff-compare--read-revisions (&optional arg mbase)
(let ((input (or arg (magit-diff-read-range-or-commit
"Compare range or commit"
nil mbase))))
(--if-let (magit-split-range input)
(-cons-to-list it)
(list input nil))))
(defun magit-ediff-read-files (revA revB &optional fileB)
"Read file in REVB, return it and the corresponding file in REVA.
When FILEB is non-nil, use this as REVB's file instead of
prompting for it."
(unless fileB
(setq fileB (magit-read-file-choice
(format "File to compare between %s and %s"
revA (or revB "the working tree"))
(magit-changed-files revA revB)
(format "No changed files between %s and %s"
revA (or revB "the working tree")))))
(list (or (car (member fileB (magit-revision-files revA)))
(cdr (assoc fileB (magit-renamed-files revB revA)))
(magit-read-file-choice
(format "File in %s to compare with %s in %s"
revA fileB (or revB "the working tree"))
(magit-changed-files revB revA)
(format "No files have changed between %s and %s"
revA revB)))
fileB))
;;;###autoload
(defun magit-ediff-dwim ()
"Compare, stage, or resolve using Ediff.
This command tries to guess what file, and what commit or range
the user wants to compare, stage, or resolve using Ediff. It
might only be able to guess either the file, or range or commit,
in which case the user is asked about the other. It might not
always guess right, in which case the appropriate `magit-ediff-*'
command has to be used explicitly. If it cannot read the user's
mind at all, then it asks the user for a command to run."
(interactive)
(magit-section-case
(hunk (save-excursion
(goto-char (magit-section-start (magit-section-parent it)))
(magit-ediff-dwim)))
(t
(let ((range (magit-diff--dwim))
(file (magit-current-file))
command revA revB)
(pcase range
((and (guard (not magit-ediff-dwim-show-on-hunks))
(or `unstaged `staged))
(setq command (if (magit-anything-unmerged-p)
#'magit-ediff-resolve
#'magit-ediff-stage)))
(`unstaged (setq command #'magit-ediff-show-unstaged))
(`staged (setq command #'magit-ediff-show-staged))
(`(commit . ,value)
(setq command #'magit-ediff-show-commit)
(setq revB value))
(`(stash . ,value)
(setq command #'magit-ediff-show-stash)
(setq revB value))
((pred stringp)
(-let [(a b) (magit-ediff-compare--read-revisions range)]
(setq command #'magit-ediff-compare)
(setq revA a)
(setq revB b)))
(_
(when (derived-mode-p 'magit-diff-mode)
(pcase (magit-diff-type)
(`committed (-let [(a b) (magit-ediff-compare--read-revisions
(car magit-refresh-args))]
(setq revA a)
(setq revB b)))
((guard (not magit-ediff-dwim-show-on-hunks))
(setq command #'magit-ediff-stage))
(`unstaged (setq command #'magit-ediff-show-unstaged))
(`staged (setq command #'magit-ediff-show-staged))
(`undefined (setq command nil))
(_ (setq command nil))))))
(cond ((not command)
(call-interactively
(magit-read-char-case
"Failed to read your mind; do you want to " t
(?c "[c]ommit" 'magit-ediff-show-commit)
(?r "[r]ange" 'magit-ediff-compare)
(?s "[s]tage" 'magit-ediff-stage)
(?v "resol[v]e" 'magit-ediff-resolve))))
((eq command 'magit-ediff-compare)
(apply 'magit-ediff-compare revA revB
(magit-ediff-read-files revA revB file)))
((eq command 'magit-ediff-show-commit)
(magit-ediff-show-commit revB))
((eq command 'magit-ediff-show-stash)
(magit-ediff-show-stash revB))
(file
(funcall command file))
(t
(call-interactively command)))))))
;;;###autoload
(defun magit-ediff-show-staged (file)
"Show staged changes using Ediff.
This only allows looking at the changes; to stage, unstage,
and discard changes using Ediff, use `magit-ediff-stage'.
FILE must be relative to the top directory of the repository."
(interactive
(list (magit-read-file-choice "Show staged changes for file"
(magit-staged-files)
"No staged files")))
(let ((conf (current-window-configuration))
(bufA (magit-get-revision-buffer "HEAD" file))
(bufB (get-buffer (concat file ".~{index}~"))))
(ediff-buffers
(or bufA (magit-find-file-noselect "HEAD" file))
(or bufB (magit-find-file-index-noselect file t))
`((lambda ()
(setq-local
ediff-quit-hook
(lambda ()
,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
(let ((magit-ediff-previous-winconf ,conf))
(run-hooks 'magit-ediff-quit-hook))))))
'ediff-buffers)))
;;;###autoload
(defun magit-ediff-show-unstaged (file)
"Show unstaged changes using Ediff.
This only allows looking at the changes; to stage, unstage,
and discard changes using Ediff, use `magit-ediff-stage'.
FILE must be relative to the top directory of the repository."
(interactive
(list (magit-read-file-choice "Show unstaged changes for file"
(magit-unstaged-files)
"No unstaged files")))
(magit-with-toplevel
(let ((conf (current-window-configuration))
(bufA (get-buffer (concat file ".~{index}~")))
(bufB (get-file-buffer file)))
(ediff-buffers
(or bufA (magit-find-file-index-noselect file t))
(or bufB (find-file-noselect file))
`((lambda ()
(setq-local
ediff-quit-hook
(lambda ()
,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
(let ((magit-ediff-previous-winconf ,conf))
(run-hooks 'magit-ediff-quit-hook))))))
'ediff-buffers))))
;;;###autoload
(defun magit-ediff-show-working-tree (file)
"Show changes between `HEAD' and working tree using Ediff.
FILE must be relative to the top directory of the repository."
(interactive
(list (magit-read-file-choice "Show changes in file"
(magit-changed-files "HEAD")
"No changed files")))
(magit-with-toplevel
(let ((conf (current-window-configuration))
(bufA (magit-get-revision-buffer "HEAD" file))
(bufB (get-file-buffer file)))
(ediff-buffers
(or bufA (magit-find-file-noselect "HEAD" file))
(or bufB (find-file-noselect file))
`((lambda ()
(setq-local
ediff-quit-hook
(lambda ()
,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
(let ((magit-ediff-previous-winconf ,conf))
(run-hooks 'magit-ediff-quit-hook))))))
'ediff-buffers))))
;;;###autoload
(defun magit-ediff-show-commit (commit)
"Show changes introduced by COMMIT using Ediff."
(interactive (list (magit-read-branch-or-commit "Revision")))
(let ((revA (concat commit "^"))
(revB commit))
(apply #'magit-ediff-compare
revA revB
(magit-ediff-read-files revA revB (magit-current-file)))))
;;;###autoload
(defun magit-ediff-show-stash (stash)
"Show changes introduced by STASH using Ediff.
`magit-ediff-show-stash-with-index' controls whether a
three-buffer Ediff is used in order to distinguish changes in the
stash that were staged."
(interactive (list (magit-read-stash "Stash")))
(-let* ((revA (concat stash "^1"))
(revB (concat stash "^2"))
(revC stash)
((fileA fileC) (magit-ediff-read-files revA revC))
(fileB fileC))
(if (and magit-ediff-show-stash-with-index
(member fileA (magit-changed-files revB revA)))
(let ((conf (current-window-configuration))
(bufA (magit-get-revision-buffer revA fileA))
(bufB (magit-get-revision-buffer revB fileB))
(bufC (magit-get-revision-buffer revC fileC)))
(ediff-buffers3
(or bufA (magit-find-file-noselect revA fileA))
(or bufB (magit-find-file-noselect revB fileB))
(or bufC (magit-find-file-noselect revC fileC))
`((lambda ()
(setq-local
ediff-quit-hook
(lambda ()
,@(unless bufA
'((ediff-kill-buffer-carefully ediff-buffer-A)))
,@(unless bufB
'((ediff-kill-buffer-carefully ediff-buffer-B)))
,@(unless bufC
'((ediff-kill-buffer-carefully ediff-buffer-C)))
(let ((magit-ediff-previous-winconf ,conf))
(run-hooks 'magit-ediff-quit-hook))))))
'ediff-buffers3))
(magit-ediff-compare revA revC fileA fileC))))
(defun magit-ediff-cleanup-auxiliary-buffers ()
(let* ((ctl-buf ediff-control-buffer)
(ctl-win (ediff-get-visible-buffer-window ctl-buf))
(ctl-frm ediff-control-frame)
(main-frame (cond ((window-live-p ediff-window-A)
(window-frame ediff-window-A))
((window-live-p ediff-window-B)
(window-frame ediff-window-B)))))
(ediff-kill-buffer-carefully ediff-diff-buffer)
(ediff-kill-buffer-carefully ediff-custom-diff-buffer)
(ediff-kill-buffer-carefully ediff-fine-diff-buffer)
(ediff-kill-buffer-carefully ediff-tmp-buffer)
(ediff-kill-buffer-carefully ediff-error-buffer)
(ediff-kill-buffer-carefully ediff-msg-buffer)
(ediff-kill-buffer-carefully ediff-debug-buffer)
(when (boundp 'ediff-patch-diagnostics)
(ediff-kill-buffer-carefully ediff-patch-diagnostics))
(cond ((and (ediff-window-display-p)
(frame-live-p ctl-frm))
(delete-frame ctl-frm))
((window-live-p ctl-win)
(delete-window ctl-win)))
(unless (ediff-multiframe-setup-p)
(ediff-kill-bottom-toolbar))
(ediff-kill-buffer-carefully ctl-buf)
(when (frame-live-p main-frame)
(select-frame main-frame))))
(defun magit-ediff-restore-previous-winconf ()
(set-window-configuration magit-ediff-previous-winconf))
(provide 'magit-ediff)
;;; magit-ediff.el ends here

View File

@ -1,340 +0,0 @@
;;; magit-extras.el --- additional functionality for Magit -*- lexical-binding: t -*-
;; Copyright (C) 2008-2018 The Magit Project Contributors
;;
;; You should have received a copy of the AUTHORS.md file which
;; lists all contributors. If not, see http://magit.vc/authors.
;; Magit 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.
;;
;; Magit 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 Magit. If not, see http://www.gnu.org/licenses.
;;; Commentary:
;; Additional functionality for Magit.
;;; Code:
(require 'magit)
(declare-function dired-do-shell-command 'dired-aux)
(declare-function dired-read-shell-command 'dired-aux)
(defgroup magit-extras nil
"Additional functionality for Magit."
:group 'magit-extensions)
;;; External Tools
(defcustom magit-gitk-executable
(or (and (eq system-type 'windows-nt)
(let ((exe (expand-file-name
"gitk" (file-name-nondirectory magit-git-executable))))
(and (file-executable-p exe) exe)))
(executable-find "gitk") "gitk")
"The Gitk executable."
:group 'magit-extras
:set-after '(magit-git-executable)
:type 'string)
;;;###autoload
(defun magit-run-git-gui ()
"Run `git gui' for the current git repository."
(interactive)
(magit-with-toplevel
(magit-process-file magit-git-executable nil 0 nil "gui")))
;;;###autoload
(defun magit-run-git-gui-blame (commit filename &optional linenum)
"Run `git gui blame' on the given FILENAME and COMMIT.
Interactively run it for the current file and the `HEAD', with a
prefix or when the current file cannot be determined let the user
choose. When the current buffer is visiting FILENAME instruct
blame to center around the line point is on."
(interactive
(let (revision filename)
(when (or current-prefix-arg
(not (setq revision "HEAD"
filename (magit-file-relative-name nil 'tracked))))
(setq revision (magit-read-branch-or-commit "Blame from revision"))
(setq filename (magit-read-file-from-rev revision "Blame file")))
(list revision filename
(and (equal filename
(ignore-errors
(magit-file-relative-name buffer-file-name)))
(line-number-at-pos)))))
(magit-with-toplevel
(apply #'magit-process-file magit-git-executable nil 0 nil "gui" "blame"
`(,@(and linenum (list (format "--line=%d" linenum)))
,commit
,filename))))
;;;###autoload
(defun magit-run-gitk ()
"Run `gitk' in the current repository."
(interactive)
(magit-process-file magit-gitk-executable nil 0))
;;;###autoload
(defun magit-run-gitk-branches ()
"Run `gitk --branches' in the current repository."
(interactive)
(magit-process-file magit-gitk-executable nil 0 nil "--branches"))
;;;###autoload
(defun magit-run-gitk-all ()
"Run `gitk --all' in the current repository."
(interactive)
(magit-process-file magit-gitk-executable nil 0 nil "--all"))
;;; Emacs Tools
;;;###autoload
(defun ido-enter-magit-status ()
"Drop into `magit-status' from file switching.
To make this command available use something like:
(add-hook \\='ido-setup-hook
(lambda ()
(define-key ido-completion-map
(kbd \"C-x g\") \\='ido-enter-magit-status)))
Starting with Emacs 25.1 the Ido keymaps are defined just once
instead of every time Ido is invoked, so now you can modify it
like pretty much every other keymap:
(define-key ido-common-completion-map
(kbd \"C-x g\") 'ido-enter-magit-status)"
(interactive)
(with-no-warnings ; FIXME these are internal variables
(setq ido-exit 'fallback fallback 'magit-status))
(exit-minibuffer))
;;;###autoload
(defun magit-dired-jump (&optional other-window)
"Visit file at point using Dired.
With a prefix argument, visit in another window. If there
is no file at point, then instead visit `default-directory'."
(interactive "P")
(dired-jump other-window (-if-let (file (magit-file-at-point))
(progn (setq file (expand-file-name file))
(if (file-directory-p file)
(concat file "/.")
file))
(concat default-directory "/."))))
;;;###autoload
(defun magit-dired-log (&optional follow)
"Show log for all marked files, or the current file."
(interactive "P")
(-if-let (topdir (magit-toplevel default-directory))
(let ((args (car (magit-log-arguments)))
(files (dired-get-marked-files nil nil #'magit-file-tracked-p)))
(unless files
(user-error "No marked file is being tracked by Git"))
(when (and follow
(not (member "--follow" args))
(not (cdr files)))
(push "--follow" args))
(magit-mode-setup-internal
#'magit-log-mode
(list (list (or (magit-get-current-branch) "HEAD"))
args
(let ((default-directory topdir))
(mapcar #'file-relative-name files)))
magit-log-buffer-file-locked))
(magit--not-inside-repository-error)))
;;;###autoload
(defun magit-do-async-shell-command (file)
"Open FILE with `dired-do-async-shell-command'.
Interactively, open the file at point."
(interactive (list (or (magit-file-at-point)
(completing-read "Act on file: "
(magit-list-files)))))
(require 'dired-aux)
(dired-do-async-shell-command
(dired-read-shell-command "& on %s: " current-prefix-arg (list file))
nil (list file)))
;;; Shift Selection
(defun magit--turn-on-shift-select-mode-p ()
(and shift-select-mode
this-command-keys-shift-translated
(not mark-active)
(not (eq (car-safe transient-mark-mode) 'only))))
;;;###autoload
(defun magit-previous-line (&optional arg try-vscroll)
"Like `previous-line' but with Magit-specific shift-selection.
Magit's selection mechanism is based on the region but selects an
area that is larger than the region. This causes `previous-line'
when invoked while holding the shift key to move up one line and
thereby select two lines. When invoked inside a hunk body this
command does not move point on the first invocation and thereby
it only selects a single line. Which inconsistency you prefer
is a matter of preference."
(declare (interactive-only
"use `forward-line' with negative argument instead."))
(interactive "p\np")
(unless arg (setq arg 1))
(let ((stay (or (magit-diff-inside-hunk-body-p)
(magit-section-position-in-heading-p))))
(if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p))
(push-mark nil nil t)
(with-no-warnings
(handle-shift-selection)
(previous-line (if stay (max (1- arg) 1) arg) try-vscroll)))))
;;;###autoload
(defun magit-next-line (&optional arg try-vscroll)
"Like `next-line' but with Magit-specific shift-selection.
Magit's selection mechanism is based on the region but selects
an area that is larger than the region. This causes `next-line'
when invoked while holding the shift key to move down one line
and thereby select two lines. When invoked inside a hunk body
this command does not move point on the first invocation and
thereby it only selects a single line. Which inconsistency you
prefer is a matter of preference."
(declare (interactive-only forward-line))
(interactive "p\np")
(unless arg (setq arg 1))
(let ((stay (or (magit-diff-inside-hunk-body-p)
(magit-section-position-in-heading-p))))
(if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p))
(push-mark nil nil t)
(with-no-warnings
(handle-shift-selection)
(next-line (if stay (max (1- arg) 1) arg) try-vscroll)))))
;;; Clean
;;;###autoload
(defun magit-clean (&optional arg)
"Remove untracked files from the working tree.
With a prefix argument also remove ignored files,
with two prefix arguments remove ignored files only.
\n(git clean -f -d [-x|-X])"
(interactive "p")
(when (yes-or-no-p (format "Remove %s files? "
(pcase arg
(1 "untracked")
(4 "untracked and ignored")
(_ "ignored"))))
(magit-wip-commit-before-change)
(magit-run-git "clean" "-f" "-d" (pcase arg (4 "-x") (16 "-X")))))
(put 'magit-clean 'disabled t)
;;; Gitignore
;;;###autoload
(defun magit-gitignore (file-or-pattern &optional local)
"Instruct Git to ignore FILE-OR-PATTERN.
With a prefix argument only ignore locally."
(interactive (list (magit-gitignore-read-pattern current-prefix-arg)
current-prefix-arg))
(let ((gitignore
(if local
(magit-git-dir (convert-standard-filename "info/exclude"))
(expand-file-name ".gitignore" (magit-toplevel)))))
(make-directory (file-name-directory gitignore) t)
(with-temp-buffer
(when (file-exists-p gitignore)
(insert-file-contents gitignore))
(goto-char (point-max))
(unless (bolp)
(insert "\n"))
(insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" file-or-pattern))
(insert "\n")
(write-region nil nil gitignore))
(if local
(magit-refresh)
(magit-run-git "add" ".gitignore"))))
;;;###autoload
(defun magit-gitignore-locally (file-or-pattern)
"Instruct Git to locally ignore FILE-OR-PATTERN."
(interactive (list (magit-gitignore-read-pattern t)))
(magit-gitignore file-or-pattern t))
(defun magit-gitignore-read-pattern (local)
(let* ((default (magit-current-file))
(choices
(delete-dups
(--mapcat
(cons (concat "/" it)
(-when-let (ext (file-name-extension it))
(list (concat "/" (file-name-directory "foo") "*." ext)
(concat "*." ext))))
(magit-untracked-files)))))
(when default
(setq default (concat "/" default))
(unless (member default choices)
(setq default (concat "*." (file-name-extension default)))
(unless (member default choices)
(setq default nil))))
(magit-completing-read (concat "File or pattern to ignore"
(and local " locally"))
choices nil nil nil nil default)))
;;; ChangeLog
;;;###autoload
(defun magit-add-change-log-entry (&optional whoami file-name other-window)
"Find change log file and add date entry and item for current change.
This differs from `add-change-log-entry' (which see) in that
it acts on the current hunk in a Magit buffer instead of on
a position in a file-visiting buffer."
(interactive (list current-prefix-arg
(prompt-for-change-log-name)))
(let (buf pos)
(save-window-excursion
(call-interactively #'magit-diff-visit-file)
(setq buf (current-buffer))
(setq pos (point)))
(save-excursion
(with-current-buffer buf
(goto-char pos)
(add-change-log-entry whoami file-name other-window)))))
;;;###autoload
(defun magit-add-change-log-entry-other-window (&optional whoami file-name)
"Find change log file in other window and add entry and item.
This differs from `add-change-log-entry-other-window' (which see)
in that it acts on the current hunk in a Magit buffer instead of
on a position in a file-visiting buffer."
(interactive (and current-prefix-arg
(list current-prefix-arg
(prompt-for-change-log-name))))
(magit-add-change-log-entry whoami file-name t))
;;; Miscellaneous
;;;###autoload
(defun magit-abort-dwim ()
"Abort current operation.
Depending on the context, this will abort a merge, a rebase, a
patch application, a cherry-pick, a revert, or a bisect."
(interactive)
(cond ((magit-merge-state) (magit-merge-abort))
((magit-rebase-in-progress-p) (magit-rebase-abort))
((magit-am-in-progress-p) (magit-am-abort))
((magit-sequencer-in-progress-p) (magit-sequencer-abort))
((magit-bisect-in-progress-p) (magit-bisect-reset))))
(provide 'magit-extras)
;;; magit-extras.el ends here

Some files were not shown because too many files have changed in this diff Show More