Working emacs prelude with ox-twbs
parent
505d3526b8
commit
3a8d215db7
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
../.dotfiles/emacs/.emacs.d/.projectile
|
|
@ -0,0 +1,3 @@
|
|||
/elpa
|
||||
/savefile
|
||||
/.cask
|
|
@ -1 +0,0 @@
|
|||
../.dotfiles/emacs/.emacs.d/CONTRIBUTING.md
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
../.dotfiles/emacs/.emacs.d/README.md
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
../.dotfiles/emacs/.emacs.d/core
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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" "\
|
||||
|
|
|
@ -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
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
Binary file not shown.
|
@ -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 "\
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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:
|
|
@ -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
|
Binary file not shown.
|
@ -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 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.
|
||||
|
||||
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 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.
|
||||
|
||||
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
|
||||
don’t assume that they don’t):
|
||||
|
||||
• 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 isn’t handled
|
||||
by ‘ghub-request’ yet. For now package authors just have to hope
|
||||
that users don’t 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 isn’t 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 haven’t 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 don’t have to worry about creating and storing a token
|
||||
yourself and can just make a request. Note however that you don’t 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 don’t 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 that’s 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 don’t 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 doesn’t matter which files already do or don’t exist when
|
||||
storing a new secret, the first file is always used.
|
||||
|
||||
Secrets are stored in ‘~/.authinfo’ in plain text. If you don’t 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 don’t 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 token’s 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 token’s 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 user’s password
|
||||
instead of a token.
|
||||
|
||||
-- Command: ghub-token-scopes
|
||||
|
||||
Because we cannot be certain that the user hasn’t 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 user’s 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 doesn’t 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-request’’s 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 shouldn’t 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:
|
|
@ -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" "\
|
||||
|
|
|
@ -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
|
|
@ -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"))
|
|
@ -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
|
Binary file not shown.
|
@ -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" "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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") "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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" "\
|
||||
|
|
|
@ -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))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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>.
|
||||
|
|
@ -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.
|
|
@ -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
|
Binary file not shown.
|
@ -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
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -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
|
Binary file not shown.
|
@ -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
|
Binary file not shown.
|
@ -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
|
Binary file not shown.
|
@ -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
|
Binary file not shown.
|
@ -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
|
Binary file not shown.
|
@ -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
|
Binary file not shown.
|
@ -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
|
Binary file not shown.
|
@ -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
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -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
|
Binary file not shown.
|
@ -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
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue