fix merge conflict

This commit is contained in:
Alexander Navarro 2024-09-14 18:20:08 -03:00
parent dc0260c20c
commit fadaa837fb
538 changed files with 6 additions and 20498 deletions

View file

@ -1,2 +1,5 @@
**/original_*
.config/lazygit/state.yml
config/tmux/plugins/*
!config/tmux/plugins/.gitkeep

View file

@ -3,9 +3,6 @@
"LuaSnip": { "branch": "master", "commit": "ce0a05ab4e2839e1c48d072c5236cce846a387bc" },
"alpha-nvim": { "branch": "main", "commit": "41283fb402713fc8b327e60907f74e46166f4cfd" },
"auto-session": { "branch": "main", "commit": "4b0728715e674ad9c18f1519127dcaed59f9981b" },
"ccc.nvim": { "branch": "main", "commit": "4fb5abaef2f2e0540fe22d4d74a9841205fff9e4" },
"chezmoi.nvim": { "branch": "main", "commit": "faf61465718424696269b2647077331b3e4605f1" },
"chezmoi.vim": { "branch": "main", "commit": "10f2692791b5e512a2c1bb4dc560b42ca5bf71fd" },
"cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" },
"cmp-cmdline": { "branch": "main", "commit": "d250c63aa13ead745e3a40f61fdd3470efde3923" },
"cmp-conventionalcommits": { "branch": "master", "commit": "a4dfacf0601130b7f8afa7c948d735c27802fb7f" },
@ -14,14 +11,13 @@
"cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" },
"cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" },
"comment-box.nvim": { "branch": "main", "commit": "06bb771690bc9df0763d14769b779062d8f12bc5" },
"conform.nvim": { "branch": "master", "commit": "0ebe875d9c306f5fc829db38492ffff2a70d8e9d" },
"conform.nvim": { "branch": "master", "commit": "cd75be867f2331b22905f47d28c0c270a69466aa" },
"debugprint.nvim": { "branch": "main", "commit": "8f2a335fb0e6ebf0291a3551e0198363437e3a38" },
"diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" },
"dressing.nvim": { "branch": "master", "commit": "6741f1062d3dc6e4755367a7e9b347b553623f04" },
"flash.nvim": { "branch": "main", "commit": "d0799ae43a581d9f190e182e2a1f389d2887c42a" },
"friendly-snippets": { "branch": "main", "commit": "45a1b96e46efe5fce8af325d4bed45feb9d29d0f" },
"gitsigns.nvim": { "branch": "main", "commit": "e9c4187c3774a46df2d086a66cf3a7e6bea4c432" },
"gopher.nvim": { "branch": "main", "commit": "f55c15ada8e02398000c04a96ef44d986cd01051" },
"grapple.nvim": { "branch": "main", "commit": "7aedc261b05a6c030397c4bc26416efbe746ebf1" },
"hurl.nvim": { "branch": "main", "commit": "d708158dda9a175c0f83cd106ea232301f4317cb" },
"indent-blankline.nvim": { "branch": "master", "commit": "65e20ab94a26d0e14acac5049b8641336819dfc7" },
@ -65,13 +61,9 @@
"trouble.nvim": { "branch": "main", "commit": "03c1fbf518bef683422a3be9643c3da190903488" },
"ts-node-action": { "branch": "master", "commit": "6d3b60754fd87963d70eadaa2f77873b447eac26" },
"twilight.nvim": { "branch": "main", "commit": "2b632c169a4b51b1eba5be90fde22a80c51c990e" },
"typescript-tools.nvim": { "branch": "master", "commit": "5da4d695d66f676eb6ea766b946e86f93baaafe7" },
"undotree": { "branch": "master", "commit": "56c684a805fe948936cda0d1b19505b84ad7e065" },
"vim-dadbod": { "branch": "master", "commit": "7888cb7164d69783d3dce4e0283decd26b82538b" },
"vim-dadbod-completion": { "branch": "master", "commit": "8c9051c1cfc73fcf5bfe9a84db7097e4f7c0180d" },
"vim-dadbod-ui": { "branch": "master", "commit": "f74a31e8c6c5a9dccc63450a09d5cd64a9294330" },
"vim-illuminate": { "branch": "master", "commit": "5eeb7951fc630682c322e88a9bbdae5c224ff0aa" },
"vim-sleuth": { "branch": "master", "commit": "1cc4557420f215d02c4d2645a748a816c220e99b" },
"zen-mode.nvim": { "branch": "main", "commit": "2694c5a2bc4dc26c7a9e74b9e2b812920c90a830" },
"zk-nvim": { "branch": "main", "commit": "dbf4eeab55b08856c9d6b6722dbff39630bb35eb" }
}

View file

@ -1,36 +0,0 @@
# extrakto help
You can give feedback or star extrakto at https://github.com/laktak/extrakto
Extrakto uses fzf. You only need to type a few keys to find your selection with a fuzzy match.
- Press *ctrl-f* to change to the next filter mode (*filter_key*)
- *word*, the default filter allows you to select words (min length=5)
- *all*, runs all filters and allows you select quotes, url, paths, etc. \
You can define your own filters as well.
- *line*, select full lines
- Press *ctrl-g* to change the grab are (see *grab_key* and configuration)
- *full*, everything from the current pane
- *window full*, everything from all panes in this window
- *recent*, everything visible with a few lines from the history (current pane)
- *window recent*, everything visible with a few lines from the history (window)
- Press *esc* or *ctrl-c* to cancel
- Use *shift-tab* to select multiple entries.
Actions that use the current selection:
- Press *tab* to insert the selection into the active tmux pane (*insert_key*).
- Press *enter* to copy the selection to the clipboard (*copy_key*).
- Press *ctrl-o* to pass the selection to the *open* command of your OS (*open_key*). \
For example if you select a URL this will open the browser.
- Press *ctrl-e* to open the selection in your $EDITOR (*edit_key*). \
This only makes sense if you select a path and if you are currently in a shell. \
extrakto will send the command to launch the editor to your active pane.
You can change most keys, define your own filters and change other configuration options. Please see the GitHub readme for instructions.

View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Christian Zangl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,191 +0,0 @@
# extrakto for tmux
![intro](https://github.com/laktak/extrakto/wiki/assets/intro1.gif)
**Output completions** - you can complete commands that require you to retype text that is already on the screen. This works everywhere, even in remote ssh sessions.
You can **fuzzy find your text** instead of selecting it by hand:
- press tmux `prefix + tab` to start extrakto
- fuzzy find the text/path/url/line
- use custom filters (`ctrl + f`)
- press
- `tab` to insert it to the current pane,
- `enter` to copy it to the clipboard,
- see other features in [HELP](HELP.md) (press `ctrl-h` in extrakto)
Use it for paths, URLs, options from a man page, git hashes, docker container names, ...
## Requirements
- [tmux](https://github.com/tmux/tmux) - popups require 3.2, otherwise extrakto will open in a split window.
- [fzf](https://github.com/junegunn/fzf)
- Python 3.6+
- Bash (tested with 5.0+, on macOS please `brew install bash` first)
see the [Wiki for Bash 4 support](https://github.com/laktak/extrakto/wiki/Bash4)
Supported clipboards:
- Linux Xorg (xclip) and Wayland (wl-copy)
- macOS (pbcopy)
- WSL (aka "Bash on Windows")
- *bring your own*, see the [Wiki](https://github.com/laktak/extrakto/wiki/) for examples (like termux)
## Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm)
Add the plugin to the list of TPM plugins in `.tmux.conf`:
set -g @plugin 'laktak/extrakto'
Hit `prefix + I` to fetch the plugin and source it.
You should now have all `extrakto` key bindings defined.
## Manual Installation
Clone the repo:
$ git clone https://github.com/laktak/extrakto ~/clone/path
Add this line to the bottom of `.tmux.conf`:
run-shell ~/clone/path/extrakto.tmux
Reload the tmux environment:
# type this in terminal
$ tmux source-file ~/.tmux.conf
You should now have all `extrakto` key bindings defined.
## Wiki
Add or look for special tips in our [wiki](https://github.com/laktak/extrakto/wiki).
## Options
To set any of these options write on your `~/.tmux.conf` file:
```
set -g <option> "<value>"
```
Where `<option>` and `<value>` are one of the specified here below
### Common Options
| Option | Default | Description |
| :--- | :---: | :--- |
| `@extrakto_grab_area` | `window full` | Whether you want extrakto to grab data from the `recent` area, the `full` pane, all current window's (`window recent`) areas or all current window's (`window full`) panes. You can also set this option to any number you want (or number preceded by "window ", e.g. "window 500"), this allows you to grab a smaller amount of data from the pane(s) than the pane's limit. For instance, you may have a really big limit for tmux history but using the same limit may end up on having slow performance on Extrakto. |
| `@extrakto_filter_order` | `word all line` | Filter modes order. The first listed mode will be the default when opening extrakto. You may use `word`, `line`, `path`, `url`, `quote`, `s-quote` or any of your own filters separated by a space. `all` applies all filters at the same time. |
### Keys
| Option | Default | Description |
| :--- | :---: | :--- |
| `@extrakto_key` | `tab` | The key binding to start. If you have any special requirements (like a custom key table) set this to 'none' and define a binding in your `.tmux.conf`. See `extrakto.tmux` for a sample. |
| `@extrakto_copy_key` | `enter` | Key to copy selection to clipboard. |
| `@extrakto_insert_key` | `tab` | Key to insert selection. |
| `@extrakto_filter_key` | `ctrl-f` | Key to toggle filter mode. |
| `@extrakto_grab_key` | `ctrl-g` | Key to toggle grab mode. |
| `@extrakto_edit_key` | `ctrl-e` | Key to run the editor. |
| `@extrakto_open_key` | `ctrl-o` | Key to run the open command. |
All but `@extrakto_key` are controlled by fzf and must follow its conventions.
### Advanced Options
| Option | Default | Description |
| :--- | :---: | :--- |
| `@extrakto_clip_tool_run` | `bg` | Set this to `tmux_osc52` to enable [remote clipboard support](https://github.com/laktak/extrakto/wiki/Remote-Copy-via-OSC52) or `fg`/`bg` to have your clipboard tool run in a foreground/background shell. |
| `@extrakto_clip_tool` | `auto` | Set this to whatever clipboard tool you would like extrakto to use to copy data into your clipboard. `auto` will try to choose the correct clipboard for your platform. |
| `@extrakto_editor` | | This defaults to `$EDITOR` if not set. |
| `@extrakto_fzf_layout` |`default` | Control the fzf layout which is "bottom-up" by default. If you prefer "top-down" layout instead set this to `reverse`. In fact, this value is passed to the fzf `--layout` parameter. Possible values are: `default`, `reverse` and `reverse-list` |
| `@extrakto_fzf_tool` | `fzf` | Set this to path of fzf if it can't be found in your `PATH`. |
| `@extrakto_fzf_unset_default_opts` | `true` | Unsets custom FZF_DEFAULT_OPTS as it can potentially cause problems in extrakto operations |
| `@extrakto_open_tool` | `auto` | Set this to path of your own tool or `auto` to use your platforms *open* implementation. |
| `@extrakto_popup_position` | `C` | Set position of the tmux popup window. Possible values are in the `display-popup` entry in `man tmux`. Set this to `x,y` to set the x and y positions to `x` and `y` respectively. |
| `@extrakto_popup_size` | `90%` | Set width and height of the tmux popup window. Set this to `w,h` to set the width to `w` and height to `h`. |
| `@extrakto_split_direction` | `a` | Whether the tmux split will be `a`uto, `p`opup, `v`ertical or `h`orizontal |
| `@extrakto_split_size` | `7` | The size of the tmux split (for vertical/horizontal) |
### Examples
```
set -g @extrakto_split_size "15"
set -g @extrakto_clip_tool "xsel --input --clipboard" # works better for nvim
set -g @extrakto_copy_key "tab" # use tab to copy to clipboard
set -g @extrakto_insert_key "enter" # use enter to insert selection
set -g @extrakto_fzf_unset_default_opts "false" # keep our custom FZF_DEFAULT_OPTS
```
## Custom Filters
You can define your own filters by creating a file in `~/.config/extrakto/extrakto.conf`:
```
[quote]
regex: ("[^"\n\r]+")
```
To override an existing filter copy it to your file first.
If you want to remove one of the alternate filters you can set it to `None`:
```toml
[quote]
alt2: None
```
See [extrakto.conf](extrakto.conf) for syntax and predefined filters.
---
# CLI
You can also use extrakto as a standalone tool to extract tokens from text.
## Installation
For now simply clone the repository and link to the tool somewhere in your path:
```
git clone https://github.com/laktak/extrakto
cd extrakto
# assuming you `export PATH=$PATH:~/.local/bin` in your `.bashrc`:
ln -s $PWD/extrakto.py ~/.local/bin/extrakto
```
Requires Python 3.6+.
## CLI Usage
```
usage: extrakto.py [-h] [--name] [-w] [-l] [--all] [-a ADD] [-p] [-u] [--alt] [-r] [-m MIN_LENGTH] [--warn-empty]
Extracts tokens from plaintext.
optional arguments:
-h, --help show this help message and exit
--name prefix filter name in the output
-w, --words extract "word" tokens
-l, --lines extract lines
--all extract using all filters defined in extrakto.conf
-a ADD, --add ADD add custom filter
-p, --paths short for -a=path
-u, --urls short for -a=url
--alt return alternate variants for each match (e.g. https://example.com and example.com)
-r, --reverse reverse output
-m MIN_LENGTH, --min-length MIN_LENGTH
minimum token length
--warn-empty warn if result is empty
```
# Contributions
Thanks go to all contributors for their ideas and PRs!
**If you make a PR, please keep it small so that it's easier to test and review. Try to create one PR per feature/bug.**
Please run `black` if you change any python code and run `shfmt` if you change any bash files.

View file

@ -1,21 +0,0 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
# top-most EditorConfig file
root = true
[*]
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 4
[*.sh]
shell_variant=bash
binary_next_line=true
switch_case_indent=true
space_redirects=true
keep_padding=false
function_next_line=false

View file

@ -1 +0,0 @@
ref: refs/heads/master

View file

@ -1,13 +0,0 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[submodule]
active = .
[remote "origin"]
url = https://git::@github.com/laktak/extrakto
fetch = +refs/heads/master:refs/remotes/origin/master
[branch "master"]
remote = origin
merge = refs/heads/master

View file

@ -1 +0,0 @@
Unnamed repository; edit this file 'description' to name the repository.

View file

@ -1,15 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
:

View file

@ -1,24 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

View file

@ -1,174 +0,0 @@
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
# An example hook script to integrate Watchman
# (https://facebook.github.io/watchman/) with git to speed up detecting
# new and modified files.
#
# The hook is passed a version (currently 2) and last update token
# formatted as a string and outputs to stdout a new update token and
# all files that have been modified since the update token. Paths must
# be relative to the root of the working tree and separated by a single NUL.
#
# To enable this hook, rename this file to "query-watchman" and set
# 'git config core.fsmonitor .git/hooks/query-watchman'
#
my ($version, $last_update_token) = @ARGV;
# Uncomment for debugging
# print STDERR "$0 $version $last_update_token\n";
# Check the hook interface version
if ($version ne 2) {
die "Unsupported query-fsmonitor hook version '$version'.\n" .
"Falling back to scanning...\n";
}
my $git_work_tree = get_working_dir();
my $retry = 1;
my $json_pkg;
eval {
require JSON::XS;
$json_pkg = "JSON::XS";
1;
} or do {
require JSON::PP;
$json_pkg = "JSON::PP";
};
launch_watchman();
sub launch_watchman {
my $o = watchman_query();
if (is_work_tree_watched($o)) {
output_result($o->{clock}, @{$o->{files}});
}
}
sub output_result {
my ($clockid, @files) = @_;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# binmode $fh, ":utf8";
# print $fh "$clockid\n@files\n";
# close $fh;
binmode STDOUT, ":utf8";
print $clockid;
print "\0";
local $, = "\0";
print @files;
}
sub watchman_clock {
my $response = qx/watchman clock "$git_work_tree"/;
die "Failed to get clock id on '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
return $json_pkg->new->utf8->decode($response);
}
sub watchman_query {
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
or die "open2() failed: $!\n" .
"Falling back to scanning...\n";
# In the query expression below we're asking for names of files that
# changed since $last_update_token but not from the .git folder.
#
# To accomplish this, we're using the "since" generator to use the
# recency index to select candidate nodes and "fields" to limit the
# output to file names only. Then we're using the "expression" term to
# further constrain the results.
my $last_update_line = "";
if (substr($last_update_token, 0, 1) eq "c") {
$last_update_token = "\"$last_update_token\"";
$last_update_line = qq[\n"since": $last_update_token,];
}
my $query = <<" END";
["query", "$git_work_tree", {$last_update_line
"fields": ["name"],
"expression": ["not", ["dirname", ".git"]]
}]
END
# Uncomment for debugging the watchman query
# open (my $fh, ">", ".git/watchman-query.json");
# print $fh $query;
# close $fh;
print CHLD_IN $query;
close CHLD_IN;
my $response = do {local $/; <CHLD_OUT>};
# Uncomment for debugging the watch response
# open ($fh, ">", ".git/watchman-response.json");
# print $fh $response;
# close $fh;
die "Watchman: command returned no output.\n" .
"Falling back to scanning...\n" if $response eq "";
die "Watchman: command returned invalid output: $response\n" .
"Falling back to scanning...\n" unless $response =~ /^\{/;
return $json_pkg->new->utf8->decode($response);
}
sub is_work_tree_watched {
my ($output) = @_;
my $error = $output->{error};
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
$retry--;
my $response = qx/watchman watch "$git_work_tree"/;
die "Failed to make watchman watch '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
$output = $json_pkg->new->utf8->decode($response);
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# close $fh;
# Watchman will always return all files on the first query so
# return the fast "everything is dirty" flag to git and do the
# Watchman query just to get it over with now so we won't pay
# the cost in git to look up each individual file.
my $o = watchman_clock();
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
output_result($o->{clock}, ("/"));
$last_update_token = $o->{clock};
eval { launch_watchman() };
return 0;
}
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
return 1;
}
sub get_working_dir {
my $working_dir;
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
$working_dir = Win32::GetCwd();
$working_dir =~ tr/\\/\//;
} else {
require Cwd;
$working_dir = Cwd::cwd();
}
return $working_dir;
}

View file

@ -1,8 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".
exec git update-server-info

View file

@ -1,14 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".
. git-sh-setup
precommit="$(git rev-parse --git-path hooks/pre-commit)"
test -x "$precommit" && exec "$precommit" ${1+"$@"}
:

View file

@ -1,49 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=$(git hash-object -t tree /dev/null)
fi
# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --type=bool hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
cat <<\EOF
Error: Attempt to add a non-ASCII file name.
This can cause problems if you want to work with people on other platforms.
To be portable it is advisable to rename the file.
If you know what you are doing you can disable this check using:
git config hooks.allownonascii true
EOF
exit 1
fi
# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

View file

@ -1,13 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git merge" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message to
# stderr if it wants to stop the merge commit.
#
# To enable this hook, rename this file to "pre-merge-commit".
. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
exec "$GIT_DIR/hooks/pre-commit"
:

View file

@ -1,53 +0,0 @@
#!/usr/bin/sh
# An example hook script to verify what is about to be pushed. Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed. If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
# <local ref> <local oid> <remote ref> <remote oid>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).
remote="$1"
url="$2"
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
while read local_ref local_oid remote_ref remote_oid
do
if test "$local_oid" = "$zero"
then
# Handle delete
:
else
if test "$remote_oid" = "$zero"
then
# New branch, examine all commits
range="$local_oid"
else
# Update to existing branch, examine new commits
range="$remote_oid..$local_oid"
fi
# Check for WIP commit
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
if test -n "$commit"
then
echo >&2 "Found WIP commit in $local_ref, not pushing"
exit 1
fi
fi
done
exit 0

View file

@ -1,169 +0,0 @@
#!/usr/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.
publish=next
basebranch="$1"
if test "$#" = 2
then
topic="refs/heads/$2"
else
topic=`git symbolic-ref HEAD` ||
exit 0 ;# we do not interrupt rebasing detached HEAD
fi
case "$topic" in
refs/heads/??/*)
;;
*)
exit 0 ;# we do not interrupt others.
;;
esac
# Now we are dealing with a topic branch being rebased
# on top of master. Is it OK to rebase it?
# Does the topic really exist?
git show-ref -q "$topic" || {
echo >&2 "No such branch $topic"
exit 1
}
# Is topic fully merged to master?
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
echo >&2 "$topic is fully merged to master; better remove it."
exit 1 ;# we could allow it, but there is no point.
fi
# Is topic ever merged to next? If so you should not be rebasing it.
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git rev-list ^master ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
not_in_topic=`git rev-list "^$topic" master`
if test -z "$not_in_topic"
then
echo >&2 "$topic is already up to date with master"
exit 1 ;# we could allow it, but there is no point.
else
exit 0
fi
else
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
/usr/bin/perl -e '
my $topic = $ARGV[0];
my $msg = "* $topic has commits already merged to public branch:\n";
my (%not_in_next) = map {
/^([0-9a-f]+) /;
($1 => 1);
} split(/\n/, $ARGV[1]);
for my $elem (map {
/^([0-9a-f]+) (.*)$/;
[$1 => $2];
} split(/\n/, $ARGV[2])) {
if (!exists $not_in_next{$elem->[0]}) {
if ($msg) {
print STDERR $msg;
undef $msg;
}
print STDERR " $elem->[1]\n";
}
}
' "$topic" "$not_in_next" "$not_in_master"
exit 1
fi
<<\DOC_END
This sample hook safeguards topic branches that have been
published from being rewound.
The workflow assumed here is:
* Once a topic branch forks from "master", "master" is never
merged into it again (either directly or indirectly).
* Once a topic branch is fully cooked and merged into "master",
it is deleted. If you need to build on top of it to correct
earlier mistakes, a new topic branch is created by forking at
the tip of the "master". This is not strictly necessary, but
it makes it easier to keep your history simple.
* Whenever you need to test or publish your changes to topic
branches, merge them into "next" branch.
The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.
With this workflow, you would want to know:
(1) ... if a topic branch has ever been merged to "next". Young
topic branches can have stupid mistakes you would rather
clean up before publishing, and things that have not been
merged into other branches can be easily rebased without
affecting other people. But once it is published, you would
not want to rewind it.
(2) ... if a topic branch has been fully merged to "master".
Then you can delete it. More importantly, you should not
build on top of it -- other people may already want to
change things related to the topic as patches against your
"master", so if you need further changes, it is better to
fork the topic (perhaps with the same name) afresh from the
tip of "master".
Let's look at this example:
o---o---o---o---o---o---o---o---o---o "next"
/ / / /
/ a---a---b A / /
/ / / /
/ / c---c---c---c B /
/ / / \ /
/ / / b---b C \ /
/ / / / \ /
---o---o---o---o---o---o---o---o---o---o---o "master"
A, B and C are topic branches.
* A has one fix since it was merged up to "next".
* B has finished. It has been fully merged up to "master" and "next",
and is ready to be deleted.
* C has not merged to "next" at all.
We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.
To compute (1):
git rev-list ^master ^topic next
git rev-list ^master next
if these match, topic has not merged in next at all.
To compute (2):
git rev-list master..topic
if this is empty, it is fully merged to "master".
DOC_END

View file

@ -1,24 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to make use of push options.
# The example simply echoes all push options that start with 'echoback='
# and rejects all pushes when the "reject" push option is used.
#
# To enable this hook, rename this file to "pre-receive".
if test -n "$GIT_PUSH_OPTION_COUNT"
then
i=0
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
do
eval "value=\$GIT_PUSH_OPTION_$i"
case "$value" in
echoback=*)
echo "echo from the pre-receive-hook: ${value#*=}" >&2
;;
reject)
exit 1
esac
i=$((i + 1))
done
fi

View file

@ -1,42 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by "git commit" with the name of the file that has the
# commit message, followed by the description of the commit
# message's source. The hook's purpose is to edit the commit
# message file. If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".
# This hook includes three examples. The first one removes the
# "# Please enter the commit message..." help message.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output. It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited. This is rarely a good idea.
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
# case "$COMMIT_SOURCE,$SHA1" in
# ,|template,)
# /usr/bin/perl -i.bak -pe '
# print "\n" . `git diff --cached --name-status -r`
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
# *) ;;
# esac
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
# if test -z "$COMMIT_SOURCE"
# then
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
# fi

View file

@ -1,78 +0,0 @@
#!/usr/bin/sh
# An example hook script to update a checked-out tree on a git push.
#
# This hook is invoked by git-receive-pack(1) when it reacts to git
# push and updates reference(s) in its repository, and when the push
# tries to update the branch that is currently checked out and the
# receive.denyCurrentBranch configuration variable is set to
# updateInstead.
#
# By default, such a push is refused if the working tree and the index
# of the remote repository has any difference from the currently
# checked out commit; when both the working tree and the index match
# the current commit, they are updated to match the newly pushed tip
# of the branch. This hook is to be used to override the default
# behaviour; however the code below reimplements the default behaviour
# as a starting point for convenient modification.
#
# The hook receives the commit with which the tip of the current
# branch is going to be updated:
commit=$1
# It can exit with a non-zero status to refuse the push (when it does
# so, it must not modify the index or the working tree).
die () {
echo >&2 "$*"
exit 1
}
# Or it can make any necessary changes to the working tree and to the
# index to bring them to the desired state when the tip of the current
# branch is updated to the new commit, and exit with a zero status.
#
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
# in order to emulate git fetch that is run in the reverse direction
# with git push, as the two-tree form of git read-tree -u -m is
# essentially the same as git switch or git checkout that switches
# branches while keeping the local changes in the working tree that do
# not interfere with the difference between the branches.
# The below is a more-or-less exact translation to shell of the C code
# for the default behaviour for git's push-to-checkout hook defined in
# the push_to_deploy() function in builtin/receive-pack.c.
#
# Note that the hook will be executed from the repository directory,
# not from the working tree, so if you want to perform operations on
# the working tree, you will have to adapt your code accordingly, e.g.
# by adding "cd .." or using relative paths.
if ! git update-index -q --ignore-submodules --refresh
then
die "Up-to-date check failed"
fi
if ! git diff-files --quiet --ignore-submodules --
then
die "Working directory has unstaged changes"
fi
# This is a rough translation of:
#
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
if git cat-file -e HEAD 2>/dev/null
then
head=HEAD
else
head=$(git hash-object -t tree --stdin </dev/null)
fi
if ! git diff-index --quiet --cached --ignore-submodules $head --
then
die "Working directory has staged changes"
fi
if ! git read-tree -u -m "$commit"
then
die "Could not update working tree to new HEAD"
fi

View file

@ -1,77 +0,0 @@
#!/usr/bin/sh
# An example hook script to validate a patch (and/or patch series) before
# sending it via email.
#
# The hook should exit with non-zero status after issuing an appropriate
# message if it wants to prevent the email(s) from being sent.
#
# To enable this hook, rename this file to "sendemail-validate".
#
# By default, it will only check that the patch(es) can be applied on top of
# the default upstream branch without conflicts in a secondary worktree. After
# validation (successful or not) of the last patch of a series, the worktree
# will be deleted.
#
# The following config variables can be set to change the default remote and
# remote ref that are used to apply the patches against:
#
# sendemail.validateRemote (default: origin)
# sendemail.validateRemoteRef (default: HEAD)
#
# Replace the TODO placeholders with appropriate checks according to your
# needs.
validate_cover_letter () {
file="$1"
# TODO: Replace with appropriate checks (e.g. spell checking).
true
}
validate_patch () {
file="$1"
# Ensure that the patch applies without conflicts.
git am -3 "$file" || return
# TODO: Replace with appropriate checks for this patch
# (e.g. checkpatch.pl).
true
}
validate_series () {
# TODO: Replace with appropriate checks for the whole series
# (e.g. quick build, coding style checks, etc.).
true
}
# main -------------------------------------------------------------------------
if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
then
remote=$(git config --default origin --get sendemail.validateRemote) &&
ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
git config --replace-all sendemail.validateWorktree "$worktree"
else
worktree=$(git config --get sendemail.validateWorktree)
fi || {
echo "sendemail-validate: error: failed to prepare worktree" >&2
exit 1
}
unset GIT_DIR GIT_WORK_TREE
cd "$worktree" &&
if grep -q "^diff --git " "$1"
then
validate_patch "$1"
else
validate_cover_letter "$1"
fi &&
if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
then
git config --unset-all sendemail.validateWorktree &&
trap 'git worktree remove -ff "$worktree"' EXIT &&
validate_series
fi

View file

@ -1,128 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to block unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
# This boolean sets whether unannotated tags will be allowed into the
# repository. By default they won't be.
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
# hooks.allowmodifytag
# This boolean sets whether a tag may be modified after creation. By default
# it won't be.
# hooks.allowdeletebranch
# This boolean sets whether deleting branches will be allowed in the
# repository. By default they won't be.
# hooks.denycreatebranch
# This boolean sets whether remotely creating branches will be denied
# in the repository. By default this is allowed.
#
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Config
allowunannotated=$(git config --type=bool hooks.allowunannotated)
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
;;
esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)
# un-annotated tag
short_refname=${refname##refs/tags/}
if [ "$allowunannotated" != "true" ]; then
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
exit 1
fi
;;
refs/tags/*,delete)
# delete tag
if [ "$allowdeletetag" != "true" ]; then
echo "*** Deleting a tag is not allowed in this repository" >&2
exit 1
fi
;;
refs/tags/*,tag)
# annotated tag
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' already exists." >&2
echo "*** Modifying a tag is not allowed in this repository." >&2
exit 1
fi
;;
refs/heads/*,commit)
# branch
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
echo "*** Creating a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/heads/*,delete)
# delete branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/remotes/*,commit)
# tracking branch
;;
refs/remotes/*,delete)
# delete tracking branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
exit 1
fi
;;
*)
# Anything else (is there anything else?)
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
exit 1
;;
esac
# --- Finished
exit 0

View file

@ -1,6 +0,0 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

View file

@ -1 +0,0 @@
0000000000000000000000000000000000000000 8796a673d46f9d2de1f37174ace39a84521aaf4b aleidk <ale.navarro.parra@gmail.com> 1699105324 -0300 clone: from https://github.com/laktak/extrakto

View file

@ -1 +0,0 @@
0000000000000000000000000000000000000000 8796a673d46f9d2de1f37174ace39a84521aaf4b aleidk <ale.navarro.parra@gmail.com> 1699105324 -0300 clone: from https://github.com/laktak/extrakto

View file

@ -1 +0,0 @@
0000000000000000000000000000000000000000 8796a673d46f9d2de1f37174ace39a84521aaf4b aleidk <ale.navarro.parra@gmail.com> 1699105324 -0300 clone: from https://github.com/laktak/extrakto

View file

@ -1,2 +0,0 @@
# pack-refs with: peeled fully-peeled sorted
8796a673d46f9d2de1f37174ace39a84521aaf4b refs/remotes/origin/master

View file

@ -1 +0,0 @@
8796a673d46f9d2de1f37174ace39a84521aaf4b

View file

@ -1 +0,0 @@
ref: refs/remotes/origin/master

View file

@ -1,20 +0,0 @@
name: Check
on: [push, pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: psf/black@stable
- name: shfmt
run: |
curl -LsS -o ~/shfmt https://github.com/mvdan/sh/releases/download/v3.1.2/shfmt_v3.1.2_linux_amd64
chmod +x ~/shfmt
~/shfmt -d scripts/ extrakto.tmux
- name: tests
run: |
python3 -m unittest discover -s tests/

View file

@ -1,215 +0,0 @@
#!/usr/bin/env python3
import os
import re
import sys
from argparse import ArgumentParser
from collections import OrderedDict
from configparser import ConfigParser
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
# "words" consist of anything but the following characters:
# [](){}=$
# unicode range 2500-27BF which includes:
# - Box Drawing
# - Block Elements
# - Geometric Shapes
# - Miscellaneous Symbols
# - Dingbats
# unicode range E000-F8FF (private use/Powerline)
# and whitespace ( \t\n\r)
RE_WORD = "[^][(){}=$\u2500-\u27BF\uE000-\uF8FF \\t\\n\\r]+"
class Extrakto:
def __init__(self, *, min_length=5, alt=False, prefix_name=False):
conf = ConfigParser(interpolation=None)
default_conf = os.path.join(SCRIPT_DIR, "extrakto.conf")
user_conf = os.path.join(
os.path.expanduser("~/.config"), "extrakto/extrakto.conf"
)
conf.read([default_conf, user_conf])
sections = conf.sections()
if not "path" in sections or not "url" in sections:
raise Exception("extrakto.conf incomplete, path and url must exist")
self.min_length = min_length
self.alt = alt
self.prefix_name = prefix_name
self.in_all = []
self.fdict = {}
for name in sections:
sect = conf[name]
alt = []
for i in range(2, 10):
key = f"alt{i}"
# if alt2, alt{n} exists as a value in a section, create a variant based on that regex
if key in sect:
alt.append(sect[key])
if sect.getboolean("in_all", fallback=True):
self.in_all.append(name)
if sect.getboolean("enabled", fallback=True):
self.fdict[name] = FilterDef(
self,
name,
regex=sect.get("regex"),
exclude=sect.get("exclude", ""),
lstrip=sect.get("lstrip", ""),
rstrip=sect.get("rstrip", ""),
alt=alt,
)
def __getitem__(self, key):
if not key in self.fdict:
raise Exception(f"Unknown filter {key}")
return self.fdict[key]
def all(self):
return self.in_all
def keys(self):
return list(self.fdict.keys())
class FilterDef:
def __init__(self, extrakto, name, *, regex, exclude, lstrip, rstrip, alt):
self.extrakto = extrakto
self.name = name
self.regex = regex
self.exclude = exclude
self.lstrip = lstrip
self.rstrip = rstrip
self.alt = alt
def filter(self, text):
res = list()
if self.extrakto.prefix_name:
add = lambda name, value: res.append(f"{name}: {value}")
else:
add = lambda name, value: res.append(value)
for m in re.finditer(self.regex, "\n" + text, flags=re.I):
item = "".join(filter(None, m.groups()))
# strip invalid characters (like punctuation or markdown syntax)
if self.lstrip:
item = item.lstrip(self.lstrip)
if self.rstrip:
item = item.rstrip(self.rstrip)
if len(item) >= self.extrakto.min_length:
if not self.exclude or not re.search(self.exclude, item, re.I):
if self.extrakto.alt:
for i, altre in enumerate(self.alt):
m = re.search(altre, item)
if m:
add(f"{self.name}{i+2}", m[1])
add(self.name, item)
return res
def get_lines(text, *, min_length=5, prefix_name=False):
lines = []
for raw_line in text.splitlines():
line = raw_line.strip()
if len(line) >= min_length:
if prefix_name:
lines.append("line: " + line)
else:
lines.append(line)
return lines
def main(parser):
args = parser.parse_args()
run_list = []
if args.words:
run_list.append("word")
if args.paths:
run_list.append("path")
if args.urls:
run_list.append("url")
run_list += args.add
res = []
# input from the terminal can cause UnicodeDecodeErrors in some instances, ignore for now
text = sys.stdin.buffer.read().decode("utf-8", "ignore")
extrakto = Extrakto(min_length=args.min_length, alt=args.alt, prefix_name=args.name)
if args.all:
run_list = extrakto.all()
if args.lines:
res += get_lines(text, min_length=args.min_length, prefix_name=args.name)
for name in run_list:
res += extrakto[name].filter(text)
if res:
if args.reverse:
res.reverse()
# remove duplicates and print
for item in OrderedDict.fromkeys(res):
print(item)
elif args.warn_empty:
print("NO MATCH - use a different filter")
if __name__ == "__main__":
parser = ArgumentParser(description="Extracts tokens from plaintext.")
parser.add_argument(
"--name", action="store_true", help="prefix filter name in the output"
)
parser.add_argument(
"-w", "--words", action="store_true", help='extract "word" tokens'
)
parser.add_argument("-l", "--lines", action="store_true", help="extract lines")
parser.add_argument(
"--all",
action="store_true",
help="extract using all filters defined in extrakto.conf",
)
parser.add_argument(
"-a", "--add", action="append", default=[], help="add custom filter"
)
parser.add_argument("-p", "--paths", action="store_true", help="short for -a=path")
parser.add_argument("-u", "--urls", action="store_true", help="short for -a=url")
parser.add_argument(
"--alt",
action="store_true",
help="return alternate variants for each match (e.g. https://example.com and example.com)",
)
parser.add_argument("-r", "--reverse", action="store_true", help="reverse output")
parser.add_argument(
"-m", "--min-length", default=5, help="minimum token length", type=int
)
parser.add_argument(
"--warn-empty", action="store_true", help="warn if result is empty"
)
main(parser)

View file

@ -1,12 +0,0 @@
#!/usr/bin/env bash
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$CURRENT_DIR/scripts/helpers.sh"
extrakto_open="$CURRENT_DIR/scripts/open.sh"
extrakto_key=$(get_option "@extrakto_key")
if [[ $(echo $extrakto_key | tr [:upper:] [:lower:]) != none ]]; then
tmux bind-key ${extrakto_key} run-shell "\"$extrakto_open\" \"#{pane_id}\""
fi

View file

@ -1,58 +0,0 @@
# extrakto filter definitions
# Define your own filters in ~/.config/extrakto/extrakto.conf
# To override an existing filter just specify the new values.
# For example, if you prefer to split words on comma as well you can define:
# [word]
# regex: ([^][(){}=$─-➿-, \t\n\r]+)
# define a section per filter
# each filter must have at least a regex containing one or more capture groups
# regex: a python regex expression
# enabled: is filter active (default True)
# in_all: is included in --all (default True)
# lstrip: characters to strip from left result
# rstrip: characters to strip from right result
# exclude: exclude result if matching
# alt2-9: alternate result (see url)
[word]
# "words" consist of anything but the following characters:
# [](){}=$
# unicode range 2500-27BF which includes:
# - Box Drawing
# - Block Elements
# - Geometric Shapes
# - Miscellaneous Symbols
# - Dingbats
# unicode range E000-F8FF (private use/Powerline)
# common editor 'whitespace' characters: ⋅↴│
# and whitespace ( \t\n\r)
# regex: [^][(){}=$\u2500-\u27BF\uE000-\uF8FF \t\n\r]+
regex: ([^][(){}=$─-➿-⋅↴│ \t\n\r]+)
lstrip: ,:;()[]{}<>'"|
rstrip: ,:;()[]{}<>'"|.
in_all: False
[path]
# separator: (?=[ \t\n]|"|\(|\[|<|\')?
# optionally starts with: (~|/)?
regex: (?:[ \t\n\"([<':]|^)(~|/)?([-~a-zA-Z0-9_+-,.]+/[^ \t\n\r|:"'$%&)>\]]*)
# exclude transfer speeds like 5k/s or m/s, and page 1/2
exclude: [kmgKMG]/s$|^\d+/\d+$
# remove invalid end characters (like punctuation or markdown syntax)
rstrip: ",):"
[url]
regex: (https?://|git@|git://|ssh://|s*ftp://|file:///)([a-zA-Z0-9?=%/_.:,;~@!#$&()*+-]*)
alt2: ://([^/? ]+)
# remove invalid end characters (like punctuation or markdown syntax)
rstrip: ",):"
[quote]
regex: ("[^"\n\r]+")
alt2: "([^"\n\r]+)"
[s-quote]
regex: ('[^'\n\r]+')
alt2: '([^'\n\r]+)'

View file

@ -1,315 +0,0 @@
#!/usr/bin/env bash
platform="$(uname)"
# first check the version of bash
if ! type mapfile &> /dev/null; then
echo "error: extrakto needs a newer Bash"
if [[ $platform == Darwin ]]; then
echo "On macOS you need to install/update it with Homebrew."
fi
read # pause
exit 1
fi
PRJ_URL=https://github.com/laktak/extrakto
current_dir="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
trigger_pane=$1
launch_mode=$2
source "$current_dir/helpers.sh"
extrakto="$current_dir/../extrakto.py"
declare -Ar COLORS=(
[RED]=$'\033[0;31m'
[GREEN]=$'\033[0;32m'
[BLUE]=$'\033[0;34m'
[PURPLE]=$'\033[0;35m'
[CYAN]=$'\033[0;36m'
[WHITE]=$'\033[0;37m'
[YELLOW]=$'\033[0;33m'
[OFF]=$'\033[0m'
[BOLD]=$'\033[1m'
)
# options; note some of the values can be overwritten by capture()
grab_area=$(get_option "@extrakto_grab_area")
clip_tool=$(get_option "@extrakto_clip_tool")
clip_tool_run=$(get_option "@extrakto_clip_tool_run")
editor=$(get_option "@extrakto_editor")
fzf_tool=$(get_option "@extrakto_fzf_tool")
open_tool=$(get_option "@extrakto_open_tool")
copy_key=$(get_option "@extrakto_copy_key")
insert_key=$(get_option "@extrakto_insert_key")
filter_key=$(get_option "@extrakto_filter_key")
open_key=$(get_option "@extrakto_open_key")
edit_key=$(get_option "@extrakto_edit_key")
grab_key=$(get_option "@extrakto_grab_key")
help_key=$(get_option "@extrakto_help_key")
fzf_layout=$(get_option "@extrakto_fzf_layout")
fzf_unset_default_opts=$(get_option "@extrakto_fzf_unset_default_opts")
capture_pane_start=$(get_capture_pane_start "$grab_area")
original_grab_area=${grab_area} # keep this so we can cycle between alternatives on fzf
# avoid side effects from FZF_DEFAULT_OPTS
if [[ $fzf_unset_default_opts == "true" ]]; then
unset FZF_DEFAULT_OPTS
fi
if [[ "$clip_tool" == "auto" ]]; then
case "$platform" in
'Linux')
if [[ $(cat /proc/sys/kernel/osrelease) =~ Microsoft|microsoft ]]; then
clip_tool='clip.exe'
elif [[ $XDG_SESSION_TYPE == "wayland" ]]; then
clip_tool='wl-copy'
else
clip_tool='xclip -i -selection clipboard >/dev/null'
fi
;;
'Darwin') clip_tool='pbcopy' ;;
*) ;;
esac
fi
if [[ "$open_tool" == "auto" ]]; then
case "$platform" in
'Linux') open_tool='xdg-open >/dev/null' ;;
'Darwin') open_tool='open' ;;
*) open_tool='' ;;
esac
fi
if [[ -z $editor ]]; then
editor="${EDITOR:-vi}"
fi
copy() {
if [[ "$clip_tool_run" == "fg" ]]; then
# run in foreground as OSC-52 copying won't work otherwise
tmux set-buffer -- "$1"
tmux run-shell "tmux show-buffer|$clip_tool"
elif [[ "$clip_tool_run" == "tmux_osc52" ]]; then
# use native tmux 3.2 OSC 52 functionality
tmux set-buffer -w -- "$1"
else
# run in background as xclip won't work otherwise
tmux set-buffer -- "$1"
tmux run-shell -b "tmux show-buffer|$clip_tool"
fi
}
open() {
if [[ -n "$open_tool" ]]; then
tmux run-shell -b "cd -- $PWD; $open_tool $1"
return 0
fi
}
capture_panes() {
local pane captured
captured=""
if [[ $grab_area =~ ^window\ ]]; then
for pane in $(tmux list-panes -F "#{pane_active}:#{pane_id}"); do
# exclude the active (for split) and trigger panes
# in popup mode the active and tigger panes are the same
if [[ $pane =~ ^0: && ${pane:2} != "$trigger_pane" ]]; then
captured+="$(tmux capture-pane -pJS ${capture_pane_start} -t ${pane:2})"
captured+=$'\n'
fi
done
fi
captured+="$(tmux capture-pane -pJS ${capture_pane_start} -t $trigger_pane)"
echo "$captured"
}
has_single_pane() {
local num_panes
num_panes=$(tmux list-panes | wc -l)
if [[ $launch_mode == popup ]]; then
[[ $num_panes == 1 ]]
else
[[ $num_panes == 2 ]]
fi
}
show_fzf_error() {
echo "error: unable to extract - check/report errors above"
echo "You can also set the fzf path in options (see readme)."
read # pause
}
capture() {
local mode header_tmpl header out res key text query
mode=$(get_next_mode "initial")
header_tmpl="${COLORS[BOLD]}${insert_key}${COLORS[OFF]}=insert"
header_tmpl+=", ${COLORS[BOLD]}${copy_key}${COLORS[OFF]}=copy"
[[ -n "$open_tool" ]] && header_tmpl+=", ${COLORS[BOLD]}${open_key}${COLORS[OFF]}=open"
header_tmpl+=", ${COLORS[BOLD]}${edit_key}${COLORS[OFF]}=edit"
header_tmpl+=", ${COLORS[BOLD]}${filter_key}${COLORS[OFF]}=filter [${COLORS[YELLOW]}${COLORS[BOLD]}:filter:${COLORS[OFF]}]"
header_tmpl+=", ${COLORS[BOLD]}${grab_key}${COLORS[OFF]}=grab [${COLORS[YELLOW]}${COLORS[BOLD]}:ga:${COLORS[OFF]}]"
header_tmpl+=", ${COLORS[BOLD]}${help_key}${COLORS[OFF]}=help"
get_cap() {
case "$mode" in
"all")
capture_panes | $extrakto --warn-empty --alt --all --name -r
;;
"line")
capture_panes | $extrakto --warn-empty -r --lines
;;
"path")
capture_panes | $extrakto --warn-empty -r --paths
;;
"url")
capture_panes | $extrakto --warn-empty -r --urls
;;
"word")
capture_panes | $extrakto --warn-empty -r --words
;;
*)
# custom filters
capture_panes | $extrakto --warn-empty -ra $mode
;;
esac
}
while true; do
header=$header_tmpl
header=${header/:ga:/$grab_area}
header=${header/:filter:/$mode}
header=${header//ctrl-/^}
# for troubleshooting add
# tee /tmp/stageN | \
# between the commands
out="$(get_cap \
| $fzf_tool \
--multi \
--print-query \
--query="$query" \
--header="$header" \
--expect=${insert_key},${copy_key},${filter_key},${edit_key},${open_key},${grab_key},${help_key},ctrl-c,esc \
--tiebreak=index \
--layout="$fzf_layout" \
--no-info)"
res=$?
{
read query
read key
mapfile -t selection
} <<< "$out"
if [[ $res -gt 0 && -z "$key" ]]; then
show_fzf_error
exit 1
fi
case "$mode" in
all)
text="${selection[@]#*: }"
;;
line)
IFS=$'\n' text="${selection[*]}"
;;
*)
text="${selection[@]}"
;;
esac
case "$key" in
"${copy_key}")
copy "$text"
return 0
;;
"${insert_key}")
tmux set-buffer -- "$text"
tmux paste-buffer -p -t $trigger_pane
return 0
;;
"${filter_key}")
mode=$(get_next_mode $mode)
;;
"${grab_key}")
# cycle between options like this:
# recent -> full -> window recent -> window full -> custom (if any) -> recent ...
if [[ $grab_area == "recent" ]]; then
if has_single_pane; then
grab_area="full"
else
grab_area="window recent"
fi
elif [[ $grab_area == "window recent" ]]; then
grab_area="full"
elif [[ $grab_area == "full" ]]; then
if has_single_pane; then
grab_area="recent"
if [[ ! "$original_grab_area" =~ ^(window )?(recent|full)$ ]]; then
grab_area="$original_grab_area"
fi
else
grab_area="window full"
fi
elif [[ $grab_area == "window full" ]]; then
grab_area="recent"
if [[ ! "$original_grab_area" =~ ^(window )?(recent|full)$ ]]; then
grab_area="$original_grab_area"
fi
else
grab_area="recent"
fi
capture_pane_start=$(get_capture_pane_start "$grab_area")
;;
"${open_key}")
open "$text"
return 0
;;
"${edit_key}")
tmux send-keys -t $trigger_pane "$editor -- $text" 'C-m'
return 0
;;
"${help_key}")
clear
less -+EF $(realpath "$current_dir/../HELP.md")
echo -e "\nSince the help page is not 'extrakt'-able:"
read -p "Do you wish to [o]pen or [c]opy the GitHub page or [a]bort? [ocA]" -d'' -s -n1 confirm
if [[ $confirm == o ]]; then
open $PRJ_URL
elif [[ $confirm == c ]]; then
copy $PRJ_URL
fi
;;
*)
return 0
;;
esac
done
}
# Entry
if [[ $launch_mode != popup ]]; then
# check terminal size, zoom pane if too small
lines=$(tput lines)
if [[ $lines -lt 7 ]]; then
tmux resize-pane -Z
fi
fi
capture

View file

@ -1,36 +0,0 @@
#!/usr/bin/env bash
current_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$current_dir/helpers.sh"
extrakto="$current_dir/extrakto.sh"
pane_id=$1
split_direction=$(get_option "@extrakto_split_direction")
if [[ $split_direction == a ]]; then
if [[ -n $(tmux list-commands popup) ]]; then
split_direction=p
else
split_direction=v
fi
fi
if [[ $split_direction == p ]]; then
IFS=, read popup_width popup_height <<< "$(get_option "@extrakto_popup_size")"
IFS=, read popup_x popup_y <<< "$(get_option "@extrakto_popup_position")"
rc=129
while [ $rc -eq 129 ]; do
tmux popup \
-w ${popup_width} \
-h ${popup_height:-$popup_width} \
-x ${popup_x} \
-y ${popup_y:-$popup_x} \
-E "${extrakto} ${pane_id} popup"
rc=$?
done
exit $rc
else
split_size=$(get_option "@extrakto_split_size")
tmux split-window -${split_direction} -l ${split_size} "tmux setw remain-on-exit off; ${extrakto} ${pane_id} split"
fi

View file

@ -1,197 +0,0 @@
#!/bin/bash
get_tmux_option() {
local option default_value option_value
option=$1
default_value=$2
option_value=$(tmux show-option -gqv "$option")
if [[ -z "$option_value" ]]; then
echo "$default_value"
else
echo "$option_value"
fi
}
get_option() {
local option=$1
case "$option" in
"@extrakto_key")
echo $(get_tmux_option $option "tab")
;;
"@extrakto_split_direction")
echo $(get_tmux_option $option "a")
;;
"@extrakto_split_size")
echo $(get_tmux_option $option "7")
;;
"@extrakto_grab_area")
echo $(get_tmux_option $option "window full")
;;
"@extrakto_clip_tool")
echo $(get_tmux_option $option "auto")
;;
"@extrakto_fzf_tool")
echo $(get_tmux_option $option "fzf")
;;
"@extrakto_open_tool")
echo $(get_tmux_option $option "auto")
;;
"@extrakto_copy_key")
echo $(get_tmux_option $option "enter")
;;
"@extrakto_insert_key")
echo $(get_tmux_option $option "tab")
;;
"@extrakto_filter_key")
echo $(get_tmux_option $option "ctrl-f")
;;
"@extrakto_open_key")
echo $(get_tmux_option $option "ctrl-o")
;;
"@extrakto_edit_key")
echo $(get_tmux_option $option "ctrl-e")
;;
"@extrakto_grab_key")
echo $(get_tmux_option $option "ctrl-g")
;;
"@extrakto_help_key")
echo $(get_tmux_option $option "ctrl-h")
;;
"@extrakto_clip_tool_run")
echo $(get_tmux_option $option "bg")
;;
"@extrakto_popup_size")
echo $(get_tmux_option $option "90%")
;;
"@extrakto_popup_position")
echo $(get_tmux_option $option "C")
;;
"@extrakto_fzf_layout")
echo $(get_tmux_option $option "default")
;;
"@extrakto_filter_order")
echo $(get_tmux_option $option "word all line")
;;
"@extrakto_fzf_unset_default_opts")
echo $(get_tmux_option $option "true")
;;
esac
}
# This returns the start point parameter for `tmux capture-pane`.
# The result will depend on how the user has set the grab area and grab size.
get_capture_pane_start() {
local grab_area capture_start history_limit
grab_area="$1"
if [[ "$grab_area" == "recent" || "$grab_area" == "window recent" ]]; then
capture_start="-10"
elif [[ "$grab_area" == "full" || "$grab_area" == "window full" ]]; then
# use the history limit, this is all the data on the pane
# if not set just go with tmux's default
history_limit=$(get_tmux_option "history-limit" "2000")
capture_start="-${history_limit}"
elif [[ "$grab_area" =~ ^window\ ]]; then
# use the user defined limit for how much to grab from every pane in the current window
capture_start="-${grab_area:7}"
else
# use the user defined limit for how much to grab from the current pane
capture_start="-${grab_area}"
fi
echo "$capture_start"
}
# Implement ordered filters list as defined by @extrakto_filter_order
declare -A next_mode
declare -a modes_list
# If there is a bogus filter mode name in the list,
# fall back to the default list of "word all line"
sanitize_modes_list() {
# in case of further "first class" filter modes implemented in the future
# add their names to the following default list and valid_modes set
local -a default=("word" "all" "line")
local -A valid_modes=(["word"]=1
["all"]=1
["line"]=1
["url"]=1
["path"]=1
["quote"]=1
["s-quote"]=1)
local invalid=false
for mode in ${modes_list[@]}; do
if [[ ${valid_modes[$mode]} -ne 1 ]]; then
invalid=true
break
fi
done
if [[ $invalid == true ]]; then
# change $modes_list to $default
for i in ${!default[@]}; do
modes_list[$i]=${default[$i]}
done
fi
}
# transform the modes_list acquired from @extrakto_filter_order into
# the more usable form of associative array
mk_next_mode_map() {
for i in ${!modes_list[@]}; do
if [[ $i -eq $((${#modes_list[@]} - 1)) ]]; then
next_mode+=([${modes_list[$i]}]=${modes_list[0]})
else
next_mode+=([${modes_list[$i]}]=${modes_list[$((i + 1))]})
fi
done
}
# initialize
modes_list_init() {
readarray -td ' ' modes_list <<< "$(get_option @extrakto_filter_order) "
unset 'modes_list[-1]'
sanitize_modes_list
mk_next_mode_map
}
# get next mode in order defined by @extrakto_filter_order
get_next_mode() {
if [[ ${#modes_list[@]} -eq 0 || ${#next_mode[@]} -le ${#modes_list[@]} ]]; then
modes_list_init
fi
local next=$1
if [ $next == "initial" ]; then
echo ${modes_list[0]}
else
echo ${next_mode[$next]}
fi
}

View file

@ -1,27 +0,0 @@
prefix [/path/in_brackets] suffix
[/path/in_brackets]
prefix [path/in_brackets] suffix
[path/in_brackets]
prefix (/path/in-parantheses) suffix
(/path/in-parantheses)
prefix (path/in-parantheses) suffix
(path/in-parantheses)
prefix "/path/in/quotes" suffix
"/path/in/quotes"
prefix "path/in/quotes" suffix
"path/in/quotes"
prefix '/path/in-single' suffix
'/path/in-single'
prefix 'path/in-single' suffix
'path/in-single'
prefix ~/home/path suffix
~/home/path
prompt:~/dot$ git status
modified: home/.tmux.conf
deleted: home/tools/bin/hello
new file: home/.laktakrc
non path: 100 k/s 50m/s 10k/s
non path: page 1/2

View file

@ -1,13 +0,0 @@
/path/in_brackets
path/in_brackets
/path/in-parantheses
path/in-parantheses
/path/in/quotes
path/in/quotes
/path/in-single
path/in-single
~/home/path
~/dot
home/.tmux.conf
home/tools/bin/hello
home/.laktakrc

View file

@ -1,20 +0,0 @@
prefix
/path/in_brackets
suffix
path/in_brackets
/path/in-parantheses
path/in-parantheses
/path/in/quotes
path/in/quotes
/path/in-single
path/in-single
~/home/path
prompt:~/dot
status
modified
home/.tmux.conf
deleted
home/tools/bin/hello
home/.laktakrc
50m/s
10k/s

View file

@ -1,3 +0,0 @@
foo "simple quote" bar
foo "first quote" foobar "second quote" bar
foo 'single quote' bar

View file

@ -1,6 +0,0 @@
simple quote
"simple quote"
first quote
"first quote"
second quote
"second quote"

View file

@ -1,6 +0,0 @@
simple
quote
first
foobar
second
single

View file

@ -1,706 +0,0 @@
Text from [teaching.idallen.com](http://teaching.idallen.com/cst8207/12f/notes/160_pathnames.html)
Unix/Linux File System and Pathnames (ROOT, absolute, relative, dot, dot dot)
Ian! D. Allen idallen@idallen.ca www.idallen.com
Fall 2012 - September to December 2012 - Updated 2017-02-25 06:30 EST
Course Home Page Course Outline All Weeks Plain Text
Updated: 2017-02-25 06:30 EST
1 The Unix/Linux File System Structure
1.1 One file system ROOT
1.2 No loops or cycles
2 Name components can contain any character except slash
3 Pathnames ("path of names") separated by slashes
3.1 Destination object may be file, directory, or other
3.2 Only one name doesnt need any slashes as separators
4 Slashes separate name components
4.1 The ROOT directory precedes the leftmost slash
5 The topmost ROOT directory / has no name
5.1 By convention, we call the ROOT directory "slash" or /
6 Only directories lead to other names
6.1 Pathnames ending in directories followed by slashes (ok)
6.2 Pathnames ending in files followed by slashes (wrong)
7 Definition of basename
8 Absolute and Relative pathnames
8.1 Absolute pathnames start with a slash /
8.1.1 Absolute pathnames always start at the system ROOT
8.2 Relative pathnames do not start with a slash
8.2.1 Relative pathnames start in the current working directory
8.2.2 Using relative pathnames saves typing
8.3 Differences between absolute and relative
8.3.1 Examples of different relative pathnames
8.3.2 Current Directory + Relative Pathname = Absolute Pathname
8.4 Pathnames such as ~, ~user, and $HOME may become Absolute
8.4.1 Leading tilde may mean absolute
8.4.2 leading $HOME variable may mean absolute
8.5 Rule for absolute pathnames in the shell
9 Relative Pathnames Exercise
9.1 Using absolute pathnames
9.2 Six slashes means seven names
9.3 Current directory /home/user/lab/foo/bar
9.4 Current directory /home/user/lab/foo
9.5 Current directory /home/user/lab
9.6 Current directory /home/user
9.7 Current directory /home
9.8 Current directory / (ROOT)
10 Dot and Dot Dot . and ..
10.1 Using ls -a to show hidden dot files
10.2 Example: /tmp/. and /./tmp
10.3 Example: /tmp/..
10.4 Example: /home/idallen/bin/../..
10.5 ROOT is its own parent directory
10.5.1 Examples: /../tmp and /../../../../../tmp
10.6 Using .. for shorter pathnames
11 Redundant but useful ./ prefix
11.1 Removing a file that looks like an option (e.g. -r)
11.2 Dont put ./ in front of relative pathnames
12 Understanding Pathnames Exercises
12.1 Relative pathnames exercise
12.2 Absolute pathnames exercise
12.3 Relative pathnames exercise with dir1
12.4 Absolute pathnames exercise with dir1
12.5 Pathnames exercises involving ROOT
12.6 Copy exercise: two pathnames
1 The Unix/Linux File System Structure
Unix/Linux files are organized within a single-tree hierarchical file system structure made up of files containing data (e.g. documents, programs), and directories (folders) that may contain other sub-directories and files.
1.1 One file system ROOT
Unlike Windows with separate multiple drive letters (A:, B:, C:, etc.) for each disk partition, the Unix/Linux file system hides the physical disk structure and has a single tree root, no matter how many disks or partitions are actually in use. There is no way to tell on what disk partition a Unix/Linux file resides by looking at its name.
1.2 No loops or cycles
The directory structure in the file system is "acyclic" following a path of directories down from the tree root into sub-directories will never lead you back toward the tree root into a "cycle" or loop.
Each file and directory has its own name.
2 Name components can contain any character except slash
The name of some object in the file system may contain any characters except the NUL character and forward slashes (/). The name may contain spaces, newlines, unprintable control characters, and characters from non-English languages.
Yes, you can have a file or directory name that is entirely made of blanks or backspace characters!
A single Linux name component is typically limited to 255 characters. Older Unix systems may have smaller limits.
3 Pathnames ("path of names") separated by slashes
A Unix/Linux pathname is a text string made up of one or more names separated by slashes. The pathname indicates how to find something in the hierarchical file system tree. Here are some examples of pathnames:
/home
/etc/passwd
/usr/bin/wc
/var/log/ntpstats/loopstats
/home/abcd0001/CST8207-16W/Assignments/assignment02
A pathname is literally a "path of names" through the hierarchy. A pathname specifies how to traverse (navigate) the hierarchical directory names in the file system to reach some destination object.
The pathname text string will contain, in order, the directories you need to go through to arrive at the destination. To do this, the pathname text string lists one or more name components separated by forward slashes, e.g. /etc/passwd, /usr/bin/wc. This is why individual file and directory names cannot themselves contain slashes slashes are used to separate the names in pathname text strings.
3.1 Destination object may be file, directory, or other
The destination object identified by the name at the far right end of a pathname text string might be a file, a directory, or some other thing such as system memory, a disk partition, or a terminal device. (Unix/Linux also uses the file system to name many things that are not ordinary files or directories.)
3.2 Only one name doesnt need any slashes as separators
A pathname with only one name component doesnt need to have any slashes to separate it from other name components, e.g. resume, cal.txt, dir.exe.
Slashes are only used to separate name components in a pathname; an individual name component can never itself contain a slash. Slashes are never part of a name component; they separate the names in a pathname.
A Linux pathname text string has an overall limit of 4,096 characters including all the individual names and all the separating slashes. Older Unix systems have a smaller limit.
Unlike Windows, Unix/Linux file system name components are separated by forward slashes (/), not backslashes (\). You can blame Microsoft for this annoying difference: Unix came first and Microsoft deliberately chose a different separator character, likely to avoid being sued by AT&T for copying the Unix file system naming.
You will note that Internet World-Wide-Web URL pathnames use the Unix forward slash separator (e.g. http://teaching.idallen.com/, because the web was invented and grew up on Unix machines.
4 Slashes separate name components
Consider the following Unix/Linux pathname text string, composed of several individual name components separated by forward slashes:
/home/idallen/bin/file.txt
Since slashes always separate name components, a pathname with four slashes in it must contain and separate five name components. In this example above, those five name components are:
"" (the nameless "ROOT" directory, to the left of the leftmost slash)
home
idallen
bin
file.txt
4.1 The ROOT directory precedes the leftmost slash
Yes, there is actually an implied directory to the left of the leftmost slash in a pathname that starts with a slash! It is the nameless "ROOT" directory, the unique tree root of the whole hierarchical file system tree, where all pathnames originate.
5 The topmost ROOT directory / has no name
Slashes always separate name components. If a pathname starts with a slash, e.g. /etc/passwd, the nameless "ROOT" directory is what begins the pathname at the far left end. This top-most ROOT directory itself has no name. It is the starting point or the tree root of the entire hierarchical Unix/Linux file system tree.
A pathname starting with a slash is called an absolute pathname. It always starts at the unique topmost file system ROOT directory.
5.1 By convention, we call the ROOT directory "slash" or /
Because it is difficult to talk about a directory that has no name, we usually (incorrectly) use the name / (slash) for the ROOT directory. This is technically wrong, because name components of a pathname cant contain slashes the slashes separate the name components. So nothing can have an actual name of /. Still, we often call the topmost ROOT directory slash (/).
Understand that when we use the name slash (/) for ROOT, we really mean "the nameless topmost ROOT directory that is to the left of the separating slash", not the slash itself.
NOTE! Do not confuse the topmost file system ROOT directory, that has no name, with an actual directory named /root that is usually the HOME directory of the system account named root. In these notes we use upper-case ROOT to refer to the root of the file system, and just root to refer to a directory named root.
6 Only directories lead to other names
To be a valid pathname ("path of names") in the file system, every name component that is to the left of the rightmost slash in a pathname must either be a directory or be a symbolic link to a directory.
Only directories can have substructure that may lead to other names.
If the pathname /home/idallen/bin/file.txt is to be a valid path of names through the file system hierarchy, the first four name components (the ROOT, home, idallen, and bin) must name existing directories. Only directories can contain and lead to other names. The four name components to the left of the rightmost slash must be names for existing directories (or be symbolic links to existing directories).
In /home/idallen/bin/file.txt, the final component name file.txt (the name to the right of the rightmost slash) is the name of the file system object itself. It might be a file or directory or anything else, though the name file.txt suggests that it is a text file name.
The final named component in the pathname, after the rightmost slash, can name anything a file, directory, symbolic link, or other special file.
6.1 Pathnames ending in directories followed by slashes (ok)
If a pathname ends in a directory name followed by a slash at the right end, e.g. /usr/bin/ or dir/, the self-referential name . (dot, or period) is assumed after the ending slash. In a directory, . refers to the directory itself. For example, all these are equivalent:
$ ls /bin
...many names print here...
$ ls /bin/
...same names print here...
$ ls /bin/.
...same names print here...
Putting one or more slashes at the right end of a directory pathname makes almost no difference it usually refers to the same directory:
$ ls /bin
...many names print here...
$ ls /bin/
...same names print here...
$ ls /bin//
...same names print here...
$ ls /bin////////////////////////////////
...same names print here...
In most pathnames ending in a directory name dir, all the names dir and dir/ and dir/. refer to the same dir directory. The trailing slash or slash-plus-dot dont make any difference.
If the last name component in a pathname is a symbolic link to a directory, e.g. /dir/symlink, trailing slashes may result in different behaviour with some commands. More on symbolic links later.
By convention, multiple adjacent slashes are treated as one slash and do not create additional implied names. The pathnames /etc/passwd and ///etc///////passwd are equivalent.
6.2 Pathnames ending in files followed by slashes (wrong)
A name component that names a file cannot be followed by a slash in a valid pathname. Only a directory name can have a slash to its right, because only directories can contain and lead to other names.
Putting a slash to the right of a non-directory (e.g. a file) results in an invalid pathname. Here is an example using the file pathname /etc/passwd:
$ wc /etc/passwd
37 89 1802 /etc/passwd # expected command output
$ wc /etc/passwd/
wc: /etc/passwd/: Not a directory # error message!
$ wc /etc/passwd/.
wc: /etc/passwd/.: Not a directory # error message!
$ wc /etc/passwd/..
wc: /etc/passwd/..: Not a directory # error message!
In a directory named /tmp/dir, the pathname /tmp/dir/../dir is the same as /tmp/dir, but if /tmp/f is a file name, the pathname /tmp/f/../f is invalid: Not a directory.
You cant put a slash after a file name component, because the file name component isnt a directory that leads to other names. You cant use a file name as if it were a directory. The error message tells you this.
7 Definition of basename
Definition of basename: The basename of any pathname is its right-most name component, to the right of its right-most slash.
pathname /home/user/file has a basename of file
pathname /usr/lib/file has a basename of file
pathname /etc/file has a basename of file
pathname /bin/grep has a basename of grep
pathname bin/grep has a basename of grep
pathname ./grep has a basename of grep
pathname grep has a basename of grep
pathname bin/. has a basename of .
pathname /etc/.. has a basename of ..
pathname lib/ has an empty basename
Several different files with the same basename can exist on a Unix/Linux system, in different directories (as in the example above of /home/user/file and /usr/lib/file that have the same basename but reside in different directories).
8 Absolute and Relative pathnames
Pathnames come in two flavours: absolute and relative:
Absolute pathnames start with a slash on the left, e.g. /etc/passwd
Relative pathnames do not start with a slash, e.g. etc/passwd
8.1 Absolute pathnames start with a slash /
A pathname that starts with a leading slash on the left is called an absolute pathname, e.g. /etc/passwd, /root/.bashrc, /bin, /, etc.
The leading slash on the left indicates that the pathname starts at the topmost nameless ROOT directory in the file system.
8.1.1 Absolute pathnames always start at the system ROOT
An absolute pathname traverses the file system hierarchy tree from the very top, always starting at the topmost ROOT directory of the file system hierarchy. The topmost ROOT directory is signalled by the leading "slash" character (/) at the start of an absolute pathname.
Absolute pathnames always start with this topmost ROOT directory slash and descend through every directory name that leads down to the destination, e.g. /home/user/file or /usr/bin/grep or /bin/ls or /etc/passwd.
The slash must always be at the start (left) of an absolute pathname.
8.2 Relative pathnames do not start with a slash
Pathnames with no leading slash on the left are called relative pathnames.
A relative pathname never starts with a slash on the left, but it may contain slashes anywhere else: /bar is not relative (it is an absolute pathname) but bar and bar/ and ./bar and ../bar and foo/bar are all relative pathnames.
A relative pathname is used along with the current working directory to avoid typing long pathnames.
8.2.1 Relative pathnames start in the current working directory
To save typing long pathnames all the time, many operating systems (including Unix/Linux and DOS) have the concept of a saved current working directory, also called current directory or working directory.
Every process in Linux can save one absolute directory pathname to be its current working directory. This working directory can be set and changed in shells using the built-in cd (change directory) command, e.g. cd /home/idallen. The current working directory can be displayed in shells using the pwd (print working directory) command.
If a process refers to a pathname that is relative (does not start with a slash), the saved current directory is always automatically prefixed to ("inserted in front of") the beginning of the pathname.
For example, if the current working directory of a process is the absolute pathname /usr/bin then all relative pathnames used by the process have /usr/bin prefixed in front of them:
In /usr/bin relative pathname foo is the same as as: /usr/bin/foo
In /usr/bin relative pathname ../etc is the same as as: /usr/bin/../etc
In /usr/bin relative pathname ./hello is the same as as: /usr/bin/./hello
In /usr/bin relative pathname . (dot) is the same as as: /usr/bin/.
In /usr/bin absolute pathname /bin is unchanged, since it is not a relative pathname.
If you then change the current working directory of the process to be the absolute pathname /home then all relative pathnames used by the process now have /home prefixed in front of them instead:
In /home relative pathname foo is the same as: /home/foo
In /home relative pathname ../etc is the same as: /home/../etc
In /home relative pathname ./hello is the same as: /home/./hello
In /home relative pathname . (dot) is the same as: /home/.
In /home absolute pathname /bin is unchanged, since it is not a relative pathname.
The saved current directory of a process is only prefixed to relative pathname references pathnames that do not start with a slash. Absolute pathnames (starting with a slash) are not affected.
Changing the saved current directory of a process changes the meaning of relative pathnames used by the process. You dont know what relative path foo means until you know what saved current directory is going to be prefixed in front of it.
The saved current working directory of a process has no effect on an absolute pathname. An absolute pathname always starts at the ROOT and doesnt depend on the saved current directory of a process. The current directory is not used when evaluating absolute pathnames. Absolute pathname /etc/passwd always always refers to the same file, no matter what the current directory of a process might be.
8.2.2 Using relative pathnames saves typing
Shells have change directory commands that let you change the saved current working directory of the shell, and of all the commands run by the shell, so that you can then type shorter relative pathnames, instead of always using long absolute pathnames. The shell change directory command is often named cd, e.g.: cd /usr/bin
Saving an appropriate current working directory prefix and using relative pathnames can make using pathnames in shell command lines much shorter to type. For example, to copy file /usr/bin/foo to /usr/bin/bar looks like this when using absolute pathnames in a shell command line:
$ cp /usr/bin/foo /usr/bin/bar # using two absolute pathnames
Setting an appropriate current working directory with cd and switching to using relative pathnames in the copy command makes the command much simpler to type:
$ cd /usr/bin
$ cp foo bar # two relative pathnames each use current directory
The relative pathname foo automatically becomes /usr/bin/foo and the relative pathname bar automatically becomes /usr/bin/bar thanks to the saved current working directory /usr/bin being prefixed to each pathname.
The saved current working directory is only prefixed to relative pathnames. Absolute pathnames remain unchanged.
8.3 Differences between absolute and relative
Absolute pathnames always refer to the same, unique destination, since absolute pathnames always start with the topmost ROOT slash and dont depend on the current directory of a process. Every process using an absolute pathname refers to the same, unique file system object, no matter what the current directory of the process is. For example, the absolute pathname /etc/passwd (starting with the topmost ROOT slash) always means the same file anywhere it is used, ignoring the current directory. The current directory is ignored for absolute pathnames.
Relative pathnames always start in the saved current directory of a process, so the final destination changes depending on the current directory of the process. The same relative pathname may refer to different things in processes that have different current directories. Changing the current directory changes the final destination of the relative pathname.
8.3.1 Examples of different relative pathnames
If the saved current working directory of a process is /home/user, and the absolute pathname of a file is /home/user/file, then a relative pathname to that file (using the saved current directory prefix) is simply file (no leading slash):
$ cd /home/user
$ cat file # relative path is same as /home/user/file
If the saved current working directory is changed to /home, then a relative pathname to that same file (using the saved current directory prefix) must be user/file:
$ cd /home
$ cat user/file # relative path is same as /home/user/file
If the current directory is changed to / (the topmost ROOT), then the relative pathname to that same file (using the saved current directory prefix) must be home/user/file:
$ cd /
$ cat home/user/file # relative path is same as /home/user/file
If your saved current working directory is the topmost ROOT directory, then absolute and relative pathnames look almost the same. The only difference is the leading slash on the absolute pathname:
$ cd /
$ cat home/user/file # relative path is same as /home/user/file
$ cat /home/user/file # equivalent absolute pathname
8.3.2 Current Directory + Relative Pathname = Absolute Pathname
The saved current directory is prefixed to a relative pathname, resulting in an absolute pathname. A current directory of /home/user plus a relative pathname of bin/script equals an absolute pathname of /home/user/bin/script.
To take an absolute pathname and turn it into a shorter relative pathname, using the saved current directory, take the absolute pathname and remove the current directory from the start, leaving a relative pathname (no leading slash). A current directory of /home/user removed from the start of an absolute pathname /home/user/bin/script leaves a relative pathname of bin/script:
$ cat /home/user/bin/script # (too) long absolute pathname
$ cd /home/user # set working directory
$ cat bin/script # use shorter relative pathname!
$ cd /home/user/bin # set better working directory
$ cat script # use even shorter relative pathname!
One of the major reasons we use relative pathnames is because they are usually much shorter to type than absolute pathnames. Choose a good working directory to make your relative pathnames short.
8.4 Pathnames such as ~, ~user, and $HOME may become Absolute
Most Unix/Linux shells have short-cuts that let you specify short versions of absolute pathnames but where the syntax of the short-cut doesnt start with a slash and so the short-cut doesnt appear to be an absolute path, even though it is.
Here are some examples:
8.4.1 Leading tilde may mean absolute
Shells may expand a leading tilde (~) on a token (command argument) to be the absolute pathname to the users home directory:
$ echo ~
/home/user
$ echo ~/bar
/home/user/bar
$ cat ~/bar # same as cat /home/user/bar
If the tilde stands alone or is immediately followed by a slash, the home directory substituted is the home directory found in the shell variable $HOME, which is usually set to the home directory of the user who is logged in (but can be changed).
Try this command line to see how the shell expands the tilde pathnames:
$ whoami
idallen
$ echo ~ ~/bin
/home/idallen /home/idallen/bin
If the tilde is followed by a valid account name, e.g. ~idallen, the shell replaces the tilde and account name with the absolute pathname of the home directory of that account, e.g. idallen may have home /home/idallen.
Try this command line to see how the shell expands the tilde pathnames for different account names:
$ echo ~mail ~uucp ~games ~root ~nosuch
/var/mail /var/spool/uucp /usr/games /root ~nosuch
Thus, ls ~idallen/bin secretly expands to and uses an absolute pathname, because, ~idallen is actually expanded (by the shell) to be the absolute path /home/idallen. Be aware of this!
8.4.2 leading $HOME variable may mean absolute
Absolute pathnames may also hide inside shell variables, e.g. $HOME/foo could be expanded by the shell to be /home/idallen/foo, an absolute pathname:
$ echo "$HOME" "$HOME/bin"
/home/idallen /home/idallen/bin
Thus, ls "$HOME/bin" secretly expands to and uses an absolute pathname, because, $HOME is actually expanded (by the shell) to be the absolute path /home/idallen. Be aware of this!
8.5 Rule for absolute pathnames in the shell
The shells modify your command line before they call the command to be executed. These modifications can turn what look like relative pathnames (e.g. ~/bin) into absolute pathnames (e.g. /home/idallen/bin):
A pathname is absolute if and only if it starts with a leading slash after all shell expansions are finished. If the expanded pathname starts with a slash, the nameless ROOT directory is always the first directory in the pathname. Otherwise, without a starting slash, the pathname is relative to the current working directory and the current working directory is prefixed to the pathname.
Watch for hidden leading slashes inserted by your shell when expanding short-cuts such as ~, ~userid, and $HOME.
9 Relative Pathnames Exercise
Given this absolute pathname to the file file.txt:
/home/user/lab/foo/bar/file.txt
Show how to rename file.txt to be file2.txt in the same directory, using relative pathnames, using as a starting point (a current directory) every directory from the bar directory up the tree to the topmost ROOT directory (giving six different answers, one for each different current working directory).
Show how the relative pathnames change depending on each of the six different current working directories.
9.1 Using absolute pathnames
If we were using absolute pathnames, the command to rename the file would be very long:
$ mv /home/user/lab/foo/bar/file.txt /home/user/lab/foo/bar/file2.txt
Below, we show how different saved current working directories make the pathname shorter.
9.2 Six slashes means seven names
The absolute file pathname /home/user/lab/foo/bar/file.txt contains six slashes, so it must have seven name components. The six name components to the left of the rightmost slash must be existing directories. There are six directories to the left of the final slash: ROOT, home, user, lab, foo, and bar.
We will start our answer in the bar directory and work our way up to the ROOT directory, giving six different answers:
9.3 Current directory /home/user/lab/foo/bar
If the current working directory is bar (actually /home/user/lab/foo/bar), then a relative path to file.txt from the bar directory is simply file.txt, e.g.
$ cd /home/user/lab/foo/bar
$ mv file.txt file2.txt
The file.txt relative pathname, used with a current working directory of /home/user/lab/foo/bar, means /home/user/lab/foo/bar/file.txt.
The file2.txt relative pathname, used with a current working directory of /home/user/lab/foo/bar, means /home/user/lab/foo/bar/file2.txt.
Now, go up one directory, from bar to its parent directory foo:
9.4 Current directory /home/user/lab/foo
If the current working directory is foo (actually /home/user/lab/foo), then a relative path to file.txt from the foo directory is bar/file.txt, e.g.
$ cd /home/user/lab/foo # or use the parent directory: cd ..
$ mv bar/file.txt bar/file2.txt
The bar/file.txt relative pathname, used with a current working directory of /home/user/lab/foo, means /home/user/lab/foo/bar/file.txt.
The bar/file2.txt relative pathname, used with a current working directory of /home/user/lab/foo, means /home/user/lab/foo/bar/file2.txt.
Now, go up one directory, from foo to its parent directory lab:
9.5 Current directory /home/user/lab
If the current directory is lab (actually /home/user/lab), then a relative path to file.txt from lab is foo/bar/file.txt, e.g.
$ cd /home/user/lab # or use the parent directory: cd ..
$ mv foo/bar/file.txt foo/bar/file2.txt
The foo/bar/file.txt relative pathname, used with a current working directory of /home/user/lab, means /home/user/lab/foo/bar/file.txt. Similar for foo/bar/file2.txt.
Now, go up one directory, from lab to its parent directory user:
9.6 Current directory /home/user
If the current directory is user, then a relative path to file.txt from user is lab/foo/bar/file.txt, e.g.
$ cd /home/user # or use the parent directory: cd ..
$ mv lab/foo/bar/file.txt lab/foo/bar/file2.txt
As with the previous examples, to find out the full pathname, concatenate the relative path to the end of the current working directory.
Now, go up one directory, from user to its parent directory home:
9.7 Current directory /home
If the current directory is home, then a relative path to file.txt from home is user/lab/foo/bar/file.txt, e.g.
$ cd /home # or use the parent directory: cd ..
$ mv user/lab/foo/bar/file.txt user/lab/foo/bar/file2.txt
Now, go up one directory, from home to its parent directory the ROOT:
9.8 Current directory / (ROOT)
If the current directory is the ROOT then a relative path to file.txt from the ROOT is home/user/lab/foo/bar/file.txt, e.g.
$ cd / # or use the parent directory: cd ..
$ mv home/user/lab/foo/bar/file.txt home/user/lab/foo/bar/file2.txt
The home/user/lab/foo/bar/file.txt relative pathname, used with a current working directory of / (ROOT), means /home/user/lab/foo/bar/file.txt.
Note that in every case above, the saved current directory when prefixed to the beginning of the relative path, gives the absolute path, e.g. in #5 above, the current directory /home prefixed to the relative pathname user/foo/bar/file.txt gives the absolute path /home/user/lab/foo/bar/file.txt this is how current directories let us write shorter relative pathnames.
Your current working directory is NOT prefixed to absolute pathnames (that start with a slash). Absolute pathnames always start at the ROOT and are always independent of your current working directory.
Your current working directory is ONLY prefixed to relative pathnames (names that do not start with a slash).
10 Dot and Dot Dot . and ..
Every Unix directory contains two special names that you cant change and cant remove:
Every Unix directory contains the name . (dot), which is a name that leads right back to the directory in which it is found.
Every directory contains the name .. (dot dot), which is a name that leads to the unique parent directory of the directory in which it is found.
10.1 Using ls -a to show hidden dot files
The two directory names . and .. are in every Unix/Linux directory, but are not normally shown by the ls command unless you use the -a (all) option to display names that begin with a leading dot (period):
$ ls
$ ls -a
. ..
$ ls -a -l
drwx------ 2 idallen idallen 40 Sep 12 01:32 .
drwxr-xr-x 26 root root 1600 Sep 12 01:33 ..
The ls command does not normally display any names that begin with a leading dot (period). Use the -a option to show them.
10.2 Example: /tmp/. and /./tmp
The directory pathname /tmp contains two directories: the leading topmost ROOT directory and tmp. The pathname /tmp/. contains three directories, ROOT, tmp, and .. The . is searched for in the tmp directory in which it is contained, and leads right back to tmp; so, /tmp and /tmp/. are equivalent.
The directory pathname /./tmp contains three directories: ROOT, ., and tmp. The . is searched for in the ROOT directory in which it is contained, and leads right back to ROOT; so, /./tmp and /tmp are equivalent.
The directory pathname /./tmp/. contains four directories: ROOT, ., tmp, and .. The first (leftmost) . is searched for in the ROOT directory; the last (rightmost) . is searched for in the tmp directory. Thus, /./tmp/. is equivalent to just: /tmp
10.3 Example: /tmp/..
The directory pathname /tmp/.. contains three directories: ROOT, tmp, and ... The .. is searched for in the tmp directory in which it is contained, and leads to the parent of the tmp directory (which is always ROOT, unless tmp is a symbolic link); so, /tmp/.. and / (ROOT) are usually equivalent.
We wont deal with symbolic links in this document. If /tmp is a symbolic link to a directory, not an actual directory, then /tmp/.. may not be the same as /. More on that later.
10.4 Example: /home/idallen/bin/../..
The directory pathname /home/idallen/bin/../.. contains six directories: ROOT, home, idallen, bin, .., and ... The first .. is searched for in the bin directory in which it is contained and leads to the parent of the bin directory, which is idallen. The second .. is therefore searched for in the idallen directory in which it is contained, and leads to the parent of the idallen directory, which is home. Thus, /home/idallen/bin/../.. is equivalent to /home (unless there are symbolic links involved).
Each .. in a pathname backs up one directory level.
If any of the pathname components are symbolic links to directories, not real directories, then the actions of . and .. are not so well behaved and the answers may differ from those given above. (We wont cover symbolic links here.) The ROOT directory can never be a symbolic link; so, /. and /.. (and /./. and /../../.., etc.) are always the same as / all by itself.
10.5 ROOT is its own parent directory
The topmost ROOT directory is the only directory that is its own parent: both . and .. are the same in the ROOT directory. If you go to the parent of the ROOT directory, you are still in the ROOT directory.
10.5.1 Examples: /../tmp and /../../../../../tmp
The directory pathname /../tmp contains three directories: ROOT, .., and tmp. The .. is searched for in the ROOT directory in which it is contained, and leads to the parent of the ROOT directory, which is (special case) also ROOT. ROOT is the only directory that is its own parent. Thus, /../tmp is the same as /tmp. Similarly, the pathname /../../../../../tmp is also the same as /tmp.
10.6 Using .. for shorter pathnames
You can use .. to make shorter pathnames when typing. Here are three examples using the cp (copy) command:
$ cp /usr/local/foo /usr/local/bin/ # 1. using absolute pathnames
$ cd /usr/local # 2. set current directory; use
$ cp foo bin/ # short relative pathnames
$ cd /usr/local/bin # 3. set current directory; use
$ cp ../foo . # short relative pathnames
From the current directory /usr/local/bin, the pathname ../foo is a relative path that goes up one level to /usr/local and then down to foo inside /usr/local giving /usr/local/foo. That file is copied into the current directory (/usr/local/bin) using the relative pathname . (/usr/local/bin/.).
Using .. and . can shorten your pathnames considerably if you choose your current directory carefully.
11 Redundant but useful ./ prefix
Putting ./ in front of any relative pathname does not change what the pathname refers to; the pathname is still relative to the current directory and still refers to the same thing. Dont do it.
Given directory dir1, these pathname arguments are all valid and all refer to the same directory dir1, so dont add the ./ because it isnt needed:
$ ls dir1 # use this
$ ls ./dir1 # same, but unnecessary
$ ls ././dir1 # same, but more unnecessary
$ ls ./././dir1 # same, but even more unnecessary
Given file name file1, these pathname arguments are also valid and all refer to the same file file1, so dont add the ./ because it isnt needed:
$ ls file1 # use this
$ ls ./file1 # same, but unnecessary
$ ls ././file1 # same, but more unnecessary
$ ls ./././file1 # same, but even more unnecessary
11.1 Removing a file that looks like an option (e.g. -r)
If you create a file (or directory) with a name starting with a dash, e.g. named -r, the file name cannot be removed without some trickery, because the name looks like an option to the rm (or rmdir) command:
$ ls # show the files in the current directory
-r # a problem file named "-r" !
$ rm -r # WRONG: does not remove file named "-r"
rm: missing operand
Try 'rm --help' for more information.
$ rmdir -r # WRONG: does not remove directory named "-r"
rmdir: invalid option -- 'r'
Try 'rmdir --help' for more information.
The trick is: You can put the superfluous ./ in front of the relative pathname to make the name stop looking like an option letter:
$ rm ./ -r # this works to remove a file named -r
-OR-
$ rmdir ./ -r # this works to remove a directory named -r
Of course, you can also use the full absolute pathname that starts with a slash, since that doesnt look like an option letter either.
$ rm /home/idallen/ -r # this works! but it's long!
$ rmdir /home/idallen/ -r # this works! but it's long!
11.2 Dont put ./ in front of relative pathnames
The above option hiding tricks are the only reason to add ./ in front of a relative pathname. Dont use ./ in front of a relative pathname unless you need to. This is superfluous:
$ touch ./foo # WRONG: ./ is not needed
$ touch foo # RIGHT
Relative pathnames do not start with a slash. Putting ./ in front of a pathname that does not start with a slash is unnecessary.
12 Understanding Pathnames Exercises
Below are some pathname exercises given this current working directory:
$ pwd
/tmp/idallen
and this sub-structure in the current directory:
$ ls -l
drwxr-xr-x 2 idallen idallen 4096 Feb 3 20:33 dir1
-rw-r--r-- 1 idallen idallen 0 Feb 3 20:33 file1
Note that I have created name dir1 as a directory and name file1 as a file for all the examples below, though I could have called them any names.
For the exercises below, assume none of the names are symbolic links (which could change the answers).
12.1 Relative pathnames exercise
All the relative pathnames below give the same output, because all these relative pathnames refer to the same (current) directory /tmp/idallen:
$ pwd
/tmp/idallen
$ ls # with no pathname arguments, ls lists the current directory
$ ls .
$ ls ./.
$ ls ././././././.
$ ls dir1/.. # the parent directory of dir1 is the current directory
$ ls ./dir1/..
$ ls dir1/../.
$ ls dir1/../././././.
$ ls ../idallen # go up to the parent, then back down into idallen
$ ls ./../idallen/./././.
$ ls ../../tmp/idallen
$ ls ../idallen/dir1/..
$ ls ../idallen/dir1/.././././.
$ ls dir1/../../idallen
$ ls ./dir1/../../idallen/.
12.2 Absolute pathnames exercise
All the absolute pathnames below also give the same output, because all these absolute pathnames refer to the same /tmp/idallen directory:
$ ls /tmp/idallen
$ ls /tmp/idallen/././.
$ ls /tmp/idallen/dir1/..
$ ls /tmp/../tmp/idallen/../idallen/dir1/..
$ ls /././tmp/./././../tmp/./././idallen/./././../././idallen/./dir1/./..
12.3 Relative pathnames exercise with dir1
All the relative pathnames below give the same output, because all these relative pathnames refer to the same sub-directory /tmp/idallen/dir1:
$ pwd
/tmp/idallen
$ ls dir1
$ ls dir1/.
$ ls ./dir1
$ ls ./dir1/.
$ ls ././././dir1/././././.
$ ls ../idallen/dir1
$ ls ../idallen/dir1/../dir1/.
$ ls ../../tmp/idallen/dir1/../../idallen/dir1/.
12.4 Absolute pathnames exercise with dir1
All the absolute pathnames below give the same output, because all these absolute pathnames refer to the same sub-directory /tmp/idallen/dir1:
$ ls /tmp/idallen/dir1
$ ls /tmp/../tmp/idallen/dir1
$ ls /tmp/../tmp/idallen/../idallen/dir1
$ ls /tmp/../tmp/idallen/../idallen/dir1/../dir1
$ ls /././tmp/./././idallen/./././dir1/./.
12.5 Pathnames exercises involving ROOT
All the relative pathnames below give the same output, because all these relative pathnames refer to the ROOT directory (from /tmp/idallen):
$ pwd
/tmp/idallen
$ ls ../..
$ ls ../../../../..
$ ls dir1/../../..
$ ls dir1/../dir1/../../..
$ ls ../idallen/../..
$ ls ../../tmp/..
$ ls ../../tmp/idallen/../..
$ ls ../../tmp/idallen/../../tmp/idallen/../../././././.
All the absolute pathnames below give the same output, because all these absolute pathnames below refer to the ROOT directory:
$ ls /
$ ls /.
$ ls /./././.
$ ls /tmp/..
$ ls /tmp/idallen/../..
$ ls /tmp/../tmp/idallen/../..
$ ls /tmp/idallen/dir1/../../..
12.6 Copy exercise: two pathnames
All these commands copy the file file1 into file2 in the same (current) directory of /tmp/idallen:
$ pwd
/tmp/idallen
$ cp file1 file2
$ cp ./file1 ./file2
$ cp ././././././file1 ././././././file2
$ cp file1 ../idallen/file2
$ cp ../idallen/file1 file2
$ cp ../idallen/file1 ../idallen/file2
$ cp ../../tmp/idallen/file1 file2
$ cp file1 ../../tmp/idallen/file2
$ cp ../../tmp/idallen/file1 ../../tmp/idallen/file2
$ cp ./././././../../tmp/idallen/file1 ./././././../../tmp/idallen/file2
$ cp /tmp/idallen/file1 /tmp/idallen/file2
$ cp /tmp/../tmp/idallen/file1 /tmp/idallen/../idallen/file2
$ cp file1 /tmp/idallen/../../tmp/idallen/file2
Author:
| Ian! D. Allen, BA, MMath - idallen@idallen.ca - Ottawa, Ontario, Canada
| Home Page: http://idallen.com/ Contact Improv: http://contactimprov.ca/
| College professor (Free/Libre GNU+Linux) at: http://teaching.idallen.com/
| Defend digital freedom: http://eff.org/ and have fun: http://fools.ca/
Plain Text - plain text version of this page in Pandoc Markdown format
Campaign for non-browser-specific HTML Valid XHTML 1.0 Transitional Valid CSS! Creative Commons by nc sa 3.0 Hacker Ideals Emblem Author Ian! D. Allen

View file

@ -1,20 +0,0 @@
path of names
"path of names"
slash
"slash"
acyclic
"acyclic"
cycle
"cycle"
(the nameless
" (the nameless "
ROOT
"ROOT"
the nameless topmost ROOT directory that is to the left of the separating slash
"the nameless topmost ROOT directory that is to the left of the separating slash"
inserted in front of
"inserted in front of"
$HOME
"$HOME"
$HOME/bin
"$HOME/bin"

View file

@ -1,175 +0,0 @@
Unix/Linux
/home/user/lab/foo/bar
/home/user/lab/foo
/home/user/lab
/home/user
/tmp/.
/./tmp
/tmp/..
/home/idallen/bin/../..
/../tmp
/../../../../../tmp
/etc/passwd
/usr/bin/wc
/var/log/ntpstats/loopstats
/home/abcd0001/CST8207-16W/Assignments/assignment02
/usr/bin/wc.
/home/idallen/bin/file.txt
/usr/bin/
/bin/
/bin/.
/bin//
/bin////////////////////////////////
dir/.
/dir/symlink
/etc/passwd/
/etc/passwd/.
/etc/passwd/..
/tmp/dir
/tmp/dir/../dir
/tmp/f
/tmp/f/../f
/home/user/file
/usr/lib/file
/etc/file
/bin/grep
bin/grep
./grep
bin/.
/etc/..
etc/passwd
/root/.bashrc
/usr/bin/grep
/bin/ls
/etc/passwd.
./bar
../bar
foo/bar
/home/idallen.
/usr/bin
/usr/bin/foo
../etc
/usr/bin/../etc
./hello
/usr/bin/./hello
/usr/bin/.
/home/foo
/home/../etc
/home/./hello
/home/.
/usr/bin/bar
user/file
home/user/file
bin/script
/home/user/bin/script.
/home/user/bin/script
/home/user/bin
~/bar
/home/user/bar
~/bin
/home/idallen
/home/idallen/bin
/var/mail
/var/spool/uucp
/usr/games
~idallen/bin
/home/idallen/foo
/home/user/lab/foo/bar/file.txt
/home/user/lab/foo/bar/file2.txt
/home/user/lab/foo/bar/file.txt.
/home/user/lab/foo/bar/file2.txt.
bar/file.txt
bar/file2.txt
foo/bar/file.txt
foo/bar/file2.txt
foo/bar/file2.txt.
lab/foo/bar/file.txt
lab/foo/bar/file2.txt
user/lab/foo/bar/file.txt
user/lab/foo/bar/file2.txt
home/user/lab/foo/bar/file.txt
home/user/lab/foo/bar/file2.txt
user/foo/bar/file.txt
/./tmp/.
/../../..
/usr/local/foo
/usr/local/bin/
/usr/local
/usr/local/bin
../foo
/usr/local/foo.
/usr/local/bin/.
./dir1
././dir1
./././dir1
./file1
././file1
./././file1
/home/idallen/
./foo
/tmp/idallen
././././././.
dir1/..
./dir1/..
dir1/../.
dir1/../././././.
../idallen
./../idallen/./././.
../../tmp/idallen
../idallen/dir1/..
../idallen/dir1/.././././.
dir1/../../idallen
./dir1/../../idallen/.
/tmp/idallen/././.
/tmp/idallen/dir1/..
/tmp/../tmp/idallen/../idallen/dir1/..
/././tmp/./././../tmp/./././idallen/./././../././idallen/./dir1/./..
/tmp/idallen/dir1
dir1/.
./dir1/.
././././dir1/././././.
../idallen/dir1
../idallen/dir1/../dir1/.
../../tmp/idallen/dir1/../../idallen/dir1/.
/tmp/../tmp/idallen/dir1
/tmp/../tmp/idallen/../idallen/dir1
/tmp/../tmp/idallen/../idallen/dir1/../dir1
/././tmp/./././idallen/./././dir1/./.
../..
../../../../..
dir1/../../..
dir1/../dir1/../../..
../idallen/../..
../../tmp/..
../../tmp/idallen/../..
../../tmp/idallen/../../tmp/idallen/../../././././.
/./././.
/tmp/idallen/../..
/tmp/../tmp/idallen/../..
/tmp/idallen/dir1/../../..
./file2
././././././file1
././././././file2
../idallen/file2
../idallen/file1
../../tmp/idallen/file1
../../tmp/idallen/file2
./././././../../tmp/idallen/file1
./././././../../tmp/idallen/file2
/tmp/idallen/file1
/tmp/idallen/file2
/tmp/../tmp/idallen/file1
/tmp/idallen/../idallen/file2
/tmp/idallen/../../tmp/idallen/file2
Free/Libre
teaching.idallen.com
http://teaching.idallen.com/cst8207/12f/notes/160_pathnames.html
http://teaching.idallen.com/
idallen.com
http://idallen.com/
contactimprov.ca
http://contactimprov.ca/
eff.org
http://eff.org/
fools.ca
http://fools.ca/

View file

@ -1,675 +0,0 @@
teaching.idallen.com
http://teaching.idallen.com/cst8207/12f/notes/160_pathnames.html
Unix/Linux
System
Pathnames
absolute
relative
Allen
idallen@idallen.ca
www.idallen.com
September
December
Updated
2017-02-25
06:30
Course
Outline
Weeks
Plain
Structure
system
loops
cycles
components
contain
character
except
slash
names
separated
slashes
Destination
object
directory
other
doesnt
separators
Slashes
separate
precedes
leftmost
topmost
convention
directories
ending
followed
files
wrong
Definition
basename
Absolute
Relative
pathnames
start
8.1.1
always
8.2.1
current
working
8.2.2
Using
saves
typing
Differences
between
8.3.1
Examples
different
8.3.2
Current
Directory
Pathname
~user
become
8.4.1
Leading
tilde
8.4.2
leading
variable
shell
Exercise
means
seven
/home/user/lab/foo/bar
/home/user/lab/foo
/home/user/lab
/home/user
/home
hidden
Example
/tmp/
/./tmp
/home/idallen/bin/../
parent
10.5.1
/../tmp
/../../../../../tmp
shorter
Redundant
useful
prefix
Removing
looks
option
Dont
front
Understanding
Exercises
exercise
exercises
involving
organized
within
single-tree
hierarchical
structure
containing
documents
programs
folders
sub-directories
Unlike
Windows
multiple
drive
letters
partition
hides
physical
single
matter
disks
partitions
actually
There
resides
looking
acyclic
following
never
toward
cycle
characters
forward
spaces
newlines
unprintable
control
non-English
languages
entirely
blanks
backspace
characters!
Linux
component
typically
limited
Older
systems
smaller
limits
pathname
string
indicates
something
examples
/etc/passwd
/usr/bin/wc
/var/log/ntpstats/loopstats
/home/abcd0001/CST8207-16W/Assignments/assignment02
literally
through
hierarchy
specifies
traverse
navigate
reach
destination
order
arrive
lists
individual
cannot
themselves
strings
identified
right
might
thing
memory
terminal
device
things
ordinary
resume
cal.txt
dir.exe
itself
overall
limit
4,096
including
separating
backslashes
blame
Microsoft
annoying
difference
first
deliberately
chose
separator
likely
avoid
being
copying
naming
Internet
World-Wide-Web
http://teaching.idallen.com/
because
invented
machines
Consider
composed
several
/home/idallen/bin/file.txt
Since
example
above
those
nameless
idallen
file.txt
there
implied
starts
slash!
unique
whole
where
originate
begins
top-most
starting
point
entire
called
Because
difficult
about
usually
incorrectly
technically
cant
nothing
actual
Still
often
Understand
really
NOTE!
confuse
named
/root
account
these
notes
upper-case
refer
valid
every
rightmost
either
symbolic
substructure
existing
links
final
anything
though
suggests
after
special
/usr/bin/
self-referential
period
assumed
refers
equivalent
...many
print
/bin/
...same
Putting
makes
almost
/bin//
/bin////////////////////////////////
trailing
slash-plus-dot
dont
/dir/symlink
result
behaviour
commands
later
adjacent
treated
create
additional
///etc///////passwd
non-directory
results
invalid
using
expected
command
output
/etc/passwd/
error
message!
/tmp/dir
/tmp/dir/../dir
/tmp/f
/tmp/f/../f
isnt
leads
message
tells
right-most
/home/user/file
/usr/lib/file
/etc/file
/bin/grep
bin/grep
./grep
/etc/
empty
Several
exist
reside
flavours
etc/passwd
/root/.bashrc
traverses
signalled
descend
/usr/bin/grep
/bin/ls
anywhere
./bar
../bar
foo/bar
along
operating
concept
saved
Every
process
changed
shells
built-in
change
/home/idallen
displayed
automatically
prefixed
inserted
beginning
/usr/bin
/usr/bin/foo
../etc
/usr/bin/../etc
./hello
/usr/bin/./hello
unchanged
since
instead
/home/foo
/home/../etc
/home/./hello
/home/
references
affected
Changing
changes
meaning
until
going
effect
depend
evaluating
Shells
Saving
appropriate
lines
/usr/bin/bar
Setting
switching
simpler
becomes
thanks
remain
ignoring
ignored
depending
processes
simply
user/file
home/user/file
resulting
bin/script
equals
/home/user/bin/script
remove
leaving
removed
leaves
pathname!
/home/user/bin
better
script
major
reasons
Choose
short
short-cuts
specify
versions
syntax
short-cut
appear
expand
token
argument
users
~/bar
/home/user/bar
stands
alone
immediately
substituted
found
which
logged
expands
whoami
~/bin
/home/idallen/bin
~idallen
replaces
~mail
~uucp
~games
~root
~nosuch
/var/mail
/var/spool/uucp
/usr/games
~idallen/bin
secretly
expanded
aware
this!
inside
variables
HOME/foo
could
/home/idallen/foo
HOME/bin
modify
before
executed
These
modifications
expansions
finished
Otherwise
without
Watch
expanding
~userid
Given
/home/user/lab/foo/bar/file.txt
rename
file2.txt
giving
answers
would
/home/user/lab/foo/bar/file2.txt
Below
contains
answer
bar/file.txt
bar/file2.txt
foo/bar/file.txt
foo/bar/file2.txt
Similar
lab/foo/bar/file.txt
lab/foo/bar/file2.txt
previous
concatenate
user/lab/foo/bar/file.txt
user/lab/foo/bar/file2.txt
home/user/lab/foo/bar/file.txt
home/user/lab/foo/bar/file2.txt
gives
user/foo/bar/file.txt
write
independent
normally
shown
unless
display
begin
drwx------
01:32
drwxr-xr-x
01:33
three
searched
contained
/./tmp/
wont
document
second
therefore
involved
backs
level
actions
behaved
differ
given
cover
/../../
still
Similarly
/usr/local/foo
/usr/local/bin/
/usr/local
/usr/local/bin
../foo
copied
shorten
considerably
choose
carefully
arguments
needed
./dir1
unnecessary
././dir1
./././dir1
file1
./file1
././file1
./././file1
trickery
rmdir
problem
WRONG
missing
operand
--help
information
trick
superfluous
letter
works
course
/home/idallen/
works!
long!
hiding
tricks
reason
touch
./foo
RIGHT
/tmp/idallen
sub-structure
20:33
-rw-r--r--
created
below
assume
././././././
dir1/
./dir1/
dir1/../
dir1/../././././
../idallen
./../idallen/./././
../../tmp/idallen
../idallen/dir1/
../idallen/dir1/.././././
dir1/../../idallen
./dir1/../../idallen/
/tmp/idallen/././
/tmp/idallen/dir1/
/tmp/../tmp/idallen/../idallen/dir1/
/././tmp/./././../tmp/./././idallen/./././../././idallen/./dir1/./
sub-directory
/tmp/idallen/dir1
././././dir1/././././
../idallen/dir1
../idallen/dir1/../dir1/
../../tmp/idallen/dir1/../../idallen/dir1/
/tmp/../tmp/idallen/dir1
/tmp/../tmp/idallen/../idallen/dir1
/tmp/../tmp/idallen/../idallen/dir1/../dir1
/././tmp/./././idallen/./././dir1/./
../../../../
dir1/../../
dir1/../dir1/../../
../idallen/../
../../tmp/
../../tmp/idallen/../
../../tmp/idallen/../../tmp/idallen/../../././././
/./././
/tmp/idallen/../
/tmp/../tmp/idallen/../
/tmp/idallen/dir1/../../
file2
./file2
././././././file1
././././././file2
../idallen/file2
../idallen/file1
../../tmp/idallen/file1
../../tmp/idallen/file2
./././././../../tmp/idallen/file1
./././././../../tmp/idallen/file2
/tmp/idallen/file1
/tmp/idallen/file2
/tmp/../tmp/idallen/file1
/tmp/idallen/../idallen/file2
/tmp/idallen/../../tmp/idallen/file2
Author
MMath
Ottawa
Ontario
Canada
http://idallen.com/
Contact
Improv
http://contactimprov.ca/
College
professor
Free/Libre
GNU+Linux
Defend
digital
freedom
http://eff.org/
http://fools.ca/
plain
version
Pandoc
Markdown
format
Campaign
non-browser-specific
Valid
XHTML
Transitional
Creative
Commons
Hacker
Ideals
Emblem

View file

@ -1,4 +0,0 @@
Some additional tests
FOO_BAR=value
BAR_FOO="longer value"
echo $FOO_BAR $BAR_FOO

View file

@ -1,6 +0,0 @@
additional
tests
FOO_BAR
value
BAR_FOO
longer

View file

@ -1,10 +0,0 @@
Unicode:
euro_€_
infinity_∞_
ruble_₽_
excluded:
note_♫_
block_drawing_│_
some_whitespace_⋅↴│_

View file

@ -1,8 +0,0 @@
Unicode
euro_€_
infinity_∞_
ruble_₽_
excluded
note_
block_drawing_
some_whitespace_

View file

@ -1,33 +0,0 @@
#!/usr/bin/env python3
import unittest
import subprocess
import os
import sys
script_dir = os.path.dirname(os.path.realpath(__file__))
def run_test(switch, name):
subprocess.run(
f"../extrakto.py {switch} --alt < assets/{name}.txt | cmp - ./assets/{name}_result{switch}.txt",
shell=True,
check=True,
cwd=script_dir,
)
class TestAssets(unittest.TestCase):
def test_all(self):
for test in ["text1", "text2", "path", "unicode", "quotes"]:
run_test("-w", test)
for test in ["text1", "path"]:
run_test("-pu", test)
for test in ["text1", "quotes"]:
run_test("-a=quote", test)
if __name__ == "__main__":
unittest.main()

View file

@ -1,25 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import unittest
from extrakto import get_lines
class TestGetLines(unittest.TestCase):
def test_get_lines_of_min_length(self):
text = """\
first line
second line with whitespace
short"""
words = [
"first line",
"second line with whitespace",
]
result = get_lines(text, min_length=6)
self.assertEqual(words, result)
if __name__ == "__main__":
unittest.main()

View file

@ -1,28 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import unittest
from extrakto import Extrakto
get_paths = Extrakto()["path"].filter
class TestGetPaths(unittest.TestCase):
def test_match_tilde_path(self):
text = "hey, test ~/tmp/test.txt etc..."
urls = ["~/tmp/test.txt"]
result = get_paths(text)
self.assertEqual(urls, result)
def test_match_full_path(self):
text = "hey, open this file /home/joe/test.txt etc..."
urls = ["/home/joe/test.txt"]
result = get_paths(text)
self.assertEqual(urls, result)
if __name__ == "__main__":
unittest.main()

View file

@ -1,66 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import unittest
from extrakto import Extrakto
get_urls = Extrakto()["url"].filter
class TestGetURLs(unittest.TestCase):
def test_match_http(self):
text = "hey, open this url http://google.com etc..."
urls = ["http://google.com"]
result = get_urls(text)
self.assertEqual(urls, result)
def test_match_https(self):
text = "hey, open this secure url https://google.com etc..."
urls = ["https://google.com"]
result = get_urls(text)
self.assertEqual(urls, result)
def test_match_ftp(self):
text = "hey, connect to this server ftp://myserver.com etc..."
urls = ["ftp://myserver.com"]
result = get_urls(text)
self.assertEqual(urls, result)
def test_match_sftp(self):
text = "hey, connect to this secure server sftp://myserver.com etc..."
urls = ["sftp://myserver.com"]
result = get_urls(text)
self.assertEqual(urls, result)
def test_match_home_path(self):
text = "hey, open this file file:////home/joe etc..."
urls = ["file:////home/joe"]
result = get_urls(text)
self.assertEqual(urls, result)
def test_match_git(self):
text = (
"hey, check out this repo git@github.com:laktak/extrakto.git"
", it's a great tmux plugin"
)
urls = ["git@github.com:laktak/extrakto.git"]
result = get_urls(text)
self.assertEqual(urls, result)
def test_match_HTTP(self):
text = "hey, open this url HTTP://GOOGLE.COM etc..."
urls = ["HTTP://GOOGLE.COM"]
result = get_urls(text)
self.assertEqual(urls, result)
if __name__ == "__main__":
unittest.main()

View file

@ -1,41 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import unittest
from extrakto import Extrakto
get_words = Extrakto(min_length=5)["word"].filter
class TestGetWords(unittest.TestCase):
def test_skip_dot_last_word_in_sentence(self):
text = "Hello world. Extrakto is an awesome plugin."
words = ["Hello", "world", "Extrakto", "awesome", "plugin"]
result = get_words(text)
self.assertEqual(words, result)
def test_box_drawing(self):
text = "other│something"
words = ["other", "something"]
result = get_words(text)
self.assertEqual(words, result)
def test_match_hidden_files(self):
text = "one /home/user/.hidden.txt two .hidden.txt three ./.hidden.txt four ../.hidden.txt"
words = [
"/home/user/.hidden.txt",
".hidden.txt",
"three",
"./.hidden.txt",
"../.hidden.txt",
]
result = get_words(text)
self.assertEqual(words, result)
if __name__ == "__main__":
unittest.main()

View file

@ -1,45 +0,0 @@
# Changelog
### master
- bugfix: "auto restore" feature stopped working
- bugfix: prevent race condition when auto-saving with locks (@v9v)
- Multiple users on a system can now each run continuum on their own.
### v3.1.0, 2015-03-14
- properly quote scripts
- bugfix: "auto restore" feature does not work on tmux `1.9a`
- bugfix: do not count `tmux source-file .tmux.conf` as a tmux process (when
checking if other tmux server is running). Previously, this caused
interpolation command not to be inserted into `status-right` because `tmux
source-file` was falsely detected as another tmux server.
- add `#{continuum_status}` status line interpolation
### v3.0.0, 2015-02-20
- rename the plugin from `tmux-resurrect-auto` to `tmux-continuum`
### v2.2.0, 2015-02-20
- document tmux multi-server behavior in the readme
- do not auto-restore tmux environment if another tmux server is already running
(we don't want to duplicate stuff)
- bugfixes for 'tmux auto start' OS X Terminal.app and iTerm scripts
- prevent saving for the first 15 minutes only when plugin is sourced the first
time (not on subsequent sources or tmux.conf reloads)
- do not start auto-saving if there's another tmux server running (we don't want
for save files from various tmux environments to override each other)
### v2.1.0, 2015-02-18
- enable "tmux auto start" for OS X
- enable customizing "tmux auto start" for OS X
- fix errors when creating a launchd plist file for auto-start on OS X
### v2.0.0, 2015-02-15
- enable automatic environment restore when tmux is started
### v1.0.0, 2015-02-12
- first working version
- run the save script in the background
- do not start saving right after tmux is started
- add a check for tmux version to the initializer script
- when interval is set to '0' autosave is disabled
- bugfix: helper files not loaded
- update readme with the instructions how to disable auto saving

View file

@ -1,15 +0,0 @@
### Contributing
Code contributions are welcome!
If you wanna contribute a bigger feature, please open a github issue so we can
discuss it together first.
### Reporting a bug
If you find a bug please report it in the issues. When reporting a bug please
attach:
- a file symlinked to `~/.tmux/resurrect/last`.
- your `.tmux.conf`
- if you're getting an error paste it to a [gist](https://gist.github.com/) and
link it in the issue

View file

@ -1,19 +0,0 @@
Copyright (C) Bruno Sutic
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,103 +0,0 @@
# tmux-continuum
Features:
- continuous saving of tmux environment
- automatic tmux start when computer/server is turned on
- automatic restore when tmux is started
Together, these features enable uninterrupted tmux usage. No matter the computer
or server restarts, if the machine is on, tmux will be there how you left it off
the last time it was used.
Tested and working on Linux, OSX and Cygwin.
#### Continuous saving
Tmux environment will be saved at an interval of 15 minutes. All the saving
happens in the background without impact to your workflow.
This action starts automatically when the plugin is installed. Note it requires
the status line to be `on` to run (since it uses a hook in status-right to run).
#### Automatic tmux start
Tmux is automatically started after the computer/server is turned on.
See the [instructions](docs/automatic_start.md) on how to enable this for your
system.
#### Automatic restore
Last saved environment is automatically restored when tmux is started.
Put `set -g @continuum-restore 'on'` in `.tmux.conf` to enable this.
Note: automatic restore happens **exclusively** on tmux server start. No other
action (e.g. sourcing `.tmux.conf`) triggers this.
#### Dependencies
`tmux 1.9` or higher, `bash`,
[tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) plugin.
### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended)
Please make sure you have
[tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) installed.
Add plugin to the list of TPM plugins in `.tmux.conf`:
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
Hit `prefix + I` to fetch the plugin and source it. The plugin will
automatically start "working" in the background, no action required.
### Manual Installation
Please make sure you have
[tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) installed.
Clone the repo:
$ git clone https://github.com/tmux-plugins/tmux-continuum ~/clone/path
Add this line to the bottom of `.tmux.conf`:
run-shell ~/clone/path/continuum.tmux
Reload TMUX environment with: `$ tmux source-file ~/.tmux.conf`
The plugin will automatically start "working" in the background, no action
required.
### Docs
- [frequently asked questions](docs/faq.md)
- [behavior when running multiple tmux servers](docs/multiple_tmux_servers.md) -
this doc is safe to skip, but you might want to read it if you're using tmux
with `-L` or `-S` flags
- [automatically start tmux after the computer is turned on](docs/automatic_start.md)
- [continuum status in tmux status line](docs/continuum_status.md)
### Other goodies
- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for
regex searches in tmux and fast match selection
- [tmux-yank](https://github.com/tmux-plugins/tmux-yank) - enables copying
highlighted text to system clipboard
- [tmux-open](https://github.com/tmux-plugins/tmux-open) - a plugin for quickly
opening highlighted file or a url
### Known Issues
- In order to be executed periodically, the plugin updates the `status-right` tmux variable. In case some plugin (usually themes) overwrites the `status-right` variable, the autosave feature stops working. To fix this issue, place the plugin last in the TPM plugins list.
### Reporting bugs and contributing
Both contributing and bug reports are welcome. Please check out
[contributing guidelines](CONTRIBUTING.md).
### License
[MIT](LICENSE.md)

View file

@ -1,47 +0,0 @@
# Automatic Tmux start
Tmux is automatically started after the computer/server is turned on.
### OS X
To enable this feature:
- put `set -g @continuum-boot 'on'` in `.tmux.conf`
- reload tmux config with this shell command: `$ tmux source-file ~/.tmux.conf`
Next time the computer is started:
- `Terminal.app` window will open and resize to maximum size
- `tmux` command will be executed in the terminal window
- if "auto restore" feature is enabled, tmux will start restoring previous env
Config options:
- `set -g @continuum-boot-options 'fullscreen'` - terminal window
will go fullscreen
- `set -g @continuum-boot-options 'iterm'` - start [iTerm](https://www.iterm2.com) instead
of `Terminal.app`
- `set -g @continuum-boot-options 'iterm,fullscreen'` - start `iTerm`
in fullscreen
- `set -g @continuum-boot-options 'kitty'` - start [kitty](https://sw.kovidgoyal.net/kitty) instead
of `Terminal.app`
- `set -g @continuum-boot-options 'kitty,fullscreen'` - start `kitty`
in fullscreen
- `set -g @continuum-boot-options 'alacritty'` - start [alacritty](https://github.com/alacritty/alacritty) instead of `Terminal.app`
- `set -g @continuum-boot-options 'alacritty,fullscreen'` - start `alacritty`
in fullscreen
Note: The first time you reboot your machine and activate this feature you may be prompted about a script requiring
access to a system program (i.e. - System Events). If this happens tmux will not start automatically and you will need
to go to `System Preferences -> Security & Privacy -> Accessability` and add the script to the list of apps that are
allowed to control your computer.
### Linux
Help with this would be greatly appreciated. Please get in touch.
#### Systemd
##### this will only start the tmux server, it will *not* start any terminal emulator
To enable automatic start with systemd:
- Put `set -g @continuum-boot 'on'` in `.tmux.conf`
- reload tmux config with this shell command: `$ tmux source-file ~/.tmux.conf`
- see [systemd](/docs/systemd_details.md) for more details about how this is implemented

View file

@ -1,17 +0,0 @@
## Continuum status in tmux status line
There is an option to display current status of tmux continuum in tmux status
line. This is done via `#{continuum_status}` interpolation and it works with
both `status-right` and `status-left` tmux native options.
Example usage:
set -g status-right 'Continuum status: #{continuum_status}'
When running, `#{continuum_status}` will show continuum save interval:
Continuum status: 15
or if continuous saving is disabled:
Continuum status: off

View file

@ -1,45 +0,0 @@
### FAQ
> Will a previous save be overwritten immediately after I start tmux?
No, first automatic save starts 15 minutes after tmux is started. If automatic
restore is not enabled, that gives you enough time to manually restore from a
previous save.
> I want to make a restore to a previous point in time, but it seems that save
is now overwritten?
Read how to [restore a previously saved environment](https://github.com/tmux-plugins/tmux-resurrect/blob/master/docs/restoring_previously_saved_environment.md)
> Will this plugin fill my hard disk?
Most likely no. A regular save file is in the range of 5Kb. And `tmux-resurrect` already has a `remove_old_backups()` routine that will ["remove resurrect files older than 30 days, but keep at least 5 copies of backup."](https://github.com/tmux-plugins/tmux-resurrect/blob/da1a7558024b8552f7262b39ed22e3d679304f99/scripts/save.sh#L271-L277)
> How do I change the save interval to i.e. 1 hour?
The interval is always measured in minutes. So setting the interval to `60`
(minutes) will do the trick. Put this in `.tmux.conf`:
set -g @continuum-save-interval '60'
and then source `tmux.conf` by executing this command in the shell
`$ tmux source-file ~/.tmux.conf`.
> How do I stop automatic saving?
Just set the save interval to `0`. Put this in `.tmux.conf`
set -g @continuum-save-interval '0'
and then source `tmux.conf` by executing this command in the shell
`$ tmux source-file ~/.tmux.conf`.
> I had automatic restore turned on, how do I disable it now?
Just remove `set -g @continuum-restore 'on'` from `tmux.conf`.
To be absolutely sure automatic restore doesn't happen, create a
`tmux_no_auto_restore` file in your home directory (command:
`$ touch ~/tmux_no_auto_restore`). Automatic restore won't happen if this file
exists.

View file

@ -1,20 +0,0 @@
### Behavior when running multiple tmux servers
(This is safe to skip if you're always running a single tmux server.)
If you're an advanced tmux user, you might be running multiple tmux servers at
the same time. Maybe you start the first tmux server with `$ tmux` and then
later another one with e.g. `$ tmux -S/tmp/foo`.
You probably don't want to "auto restore" the same environment in the second
tmux that uses `/tmp/foo` socket. You also probably don't want two tmux
environments both having "auto save" feature on (think about overwrites).
This plugin handles multi-server scenario by giving precedence to the tmux
server that was first started.
In the above example, the server started with `$ tmux` will do "auto
restore" (if enabled) and will start "auto saving".
"Auto restore" or "auto saving" **will not** happen for the second server that
was started later with the `$ tmux -S/tmp/foo` command. The plugin will
detect the presence of another server (`$ tmux`) and give it precedence.

View file

@ -1,13 +0,0 @@
# Systemd automatic start for tmux
The first time tmux starts when `@continuum-boot` is set to 'on' tmux-continuum will generate a user level systemd unit file which it will save to `${HOME}/.config/systemd/user/tmux.service` and enable it. From then on when that user logs in, either through a GUI session or on the console or via ssh, Systemd will start the tmux server.
The command used to start the tmux server is determined via the `@continuum-systemd-start-cmd` option that can be set in .tmux.conf. (Remember to reload your configuration with `tmux source ~/.tmux.conf` afterwards.
The default command to use is `new-session -d`. If you want more control over what sessions get started then you should set up your sessions in tmux.conf and set `@continuum-systemd-start-cmd = 'start-server'`. As this will be executed as part of systemd's ExecStart statement there will be no shell parsing. See [Systemd manual](http://www.freedesktop.org/software/systemd/man/systemd.service.html#Command%20lines) for more details.
To control the tmux service you can use all the standard `systemctl` commands using the `--user` argument. eg to see if the tmux server has started:
systemctl --user status tmux.service

View file

@ -1 +0,0 @@
ref: refs/heads/master

View file

@ -1,13 +0,0 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[submodule]
active = .
[remote "origin"]
url = https://git::@github.com/tmux-plugins/tmux-continuum
fetch = +refs/heads/master:refs/remotes/origin/master
[branch "master"]
remote = origin
merge = refs/heads/master

View file

@ -1 +0,0 @@
Unnamed repository; edit this file 'description' to name the repository.

View file

@ -1,15 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
:

View file

@ -1,24 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

View file

@ -1,174 +0,0 @@
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
# An example hook script to integrate Watchman
# (https://facebook.github.io/watchman/) with git to speed up detecting
# new and modified files.
#
# The hook is passed a version (currently 2) and last update token
# formatted as a string and outputs to stdout a new update token and
# all files that have been modified since the update token. Paths must
# be relative to the root of the working tree and separated by a single NUL.
#
# To enable this hook, rename this file to "query-watchman" and set
# 'git config core.fsmonitor .git/hooks/query-watchman'
#
my ($version, $last_update_token) = @ARGV;
# Uncomment for debugging
# print STDERR "$0 $version $last_update_token\n";
# Check the hook interface version
if ($version ne 2) {
die "Unsupported query-fsmonitor hook version '$version'.\n" .
"Falling back to scanning...\n";
}
my $git_work_tree = get_working_dir();
my $retry = 1;
my $json_pkg;
eval {
require JSON::XS;
$json_pkg = "JSON::XS";
1;
} or do {
require JSON::PP;
$json_pkg = "JSON::PP";
};
launch_watchman();
sub launch_watchman {
my $o = watchman_query();
if (is_work_tree_watched($o)) {
output_result($o->{clock}, @{$o->{files}});
}
}
sub output_result {
my ($clockid, @files) = @_;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# binmode $fh, ":utf8";
# print $fh "$clockid\n@files\n";
# close $fh;
binmode STDOUT, ":utf8";
print $clockid;
print "\0";
local $, = "\0";
print @files;
}
sub watchman_clock {
my $response = qx/watchman clock "$git_work_tree"/;
die "Failed to get clock id on '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
return $json_pkg->new->utf8->decode($response);
}
sub watchman_query {
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
or die "open2() failed: $!\n" .
"Falling back to scanning...\n";
# In the query expression below we're asking for names of files that
# changed since $last_update_token but not from the .git folder.
#
# To accomplish this, we're using the "since" generator to use the
# recency index to select candidate nodes and "fields" to limit the
# output to file names only. Then we're using the "expression" term to
# further constrain the results.
my $last_update_line = "";
if (substr($last_update_token, 0, 1) eq "c") {
$last_update_token = "\"$last_update_token\"";
$last_update_line = qq[\n"since": $last_update_token,];
}
my $query = <<" END";
["query", "$git_work_tree", {$last_update_line
"fields": ["name"],
"expression": ["not", ["dirname", ".git"]]
}]
END
# Uncomment for debugging the watchman query
# open (my $fh, ">", ".git/watchman-query.json");
# print $fh $query;
# close $fh;
print CHLD_IN $query;
close CHLD_IN;
my $response = do {local $/; <CHLD_OUT>};
# Uncomment for debugging the watch response
# open ($fh, ">", ".git/watchman-response.json");
# print $fh $response;
# close $fh;
die "Watchman: command returned no output.\n" .
"Falling back to scanning...\n" if $response eq "";
die "Watchman: command returned invalid output: $response\n" .
"Falling back to scanning...\n" unless $response =~ /^\{/;
return $json_pkg->new->utf8->decode($response);
}
sub is_work_tree_watched {
my ($output) = @_;
my $error = $output->{error};
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
$retry--;
my $response = qx/watchman watch "$git_work_tree"/;
die "Failed to make watchman watch '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
$output = $json_pkg->new->utf8->decode($response);
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# close $fh;
# Watchman will always return all files on the first query so
# return the fast "everything is dirty" flag to git and do the
# Watchman query just to get it over with now so we won't pay
# the cost in git to look up each individual file.
my $o = watchman_clock();
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
output_result($o->{clock}, ("/"));
$last_update_token = $o->{clock};
eval { launch_watchman() };
return 0;
}
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
return 1;
}
sub get_working_dir {
my $working_dir;
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
$working_dir = Win32::GetCwd();
$working_dir =~ tr/\\/\//;
} else {
require Cwd;
$working_dir = Cwd::cwd();
}
return $working_dir;
}

View file

@ -1,8 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".
exec git update-server-info

View file

@ -1,14 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".
. git-sh-setup
precommit="$(git rev-parse --git-path hooks/pre-commit)"
test -x "$precommit" && exec "$precommit" ${1+"$@"}
:

View file

@ -1,49 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=$(git hash-object -t tree /dev/null)
fi
# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --type=bool hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
cat <<\EOF
Error: Attempt to add a non-ASCII file name.
This can cause problems if you want to work with people on other platforms.
To be portable it is advisable to rename the file.
If you know what you are doing you can disable this check using:
git config hooks.allownonascii true
EOF
exit 1
fi
# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

View file

@ -1,13 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git merge" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message to
# stderr if it wants to stop the merge commit.
#
# To enable this hook, rename this file to "pre-merge-commit".
. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
exec "$GIT_DIR/hooks/pre-commit"
:

View file

@ -1,53 +0,0 @@
#!/usr/bin/sh
# An example hook script to verify what is about to be pushed. Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed. If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
# <local ref> <local oid> <remote ref> <remote oid>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).
remote="$1"
url="$2"
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
while read local_ref local_oid remote_ref remote_oid
do
if test "$local_oid" = "$zero"
then
# Handle delete
:
else
if test "$remote_oid" = "$zero"
then
# New branch, examine all commits
range="$local_oid"
else
# Update to existing branch, examine new commits
range="$remote_oid..$local_oid"
fi
# Check for WIP commit
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
if test -n "$commit"
then
echo >&2 "Found WIP commit in $local_ref, not pushing"
exit 1
fi
fi
done
exit 0

View file

@ -1,169 +0,0 @@
#!/usr/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.
publish=next
basebranch="$1"
if test "$#" = 2
then
topic="refs/heads/$2"
else
topic=`git symbolic-ref HEAD` ||
exit 0 ;# we do not interrupt rebasing detached HEAD
fi
case "$topic" in
refs/heads/??/*)
;;
*)
exit 0 ;# we do not interrupt others.
;;
esac
# Now we are dealing with a topic branch being rebased
# on top of master. Is it OK to rebase it?
# Does the topic really exist?
git show-ref -q "$topic" || {
echo >&2 "No such branch $topic"
exit 1
}
# Is topic fully merged to master?
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
echo >&2 "$topic is fully merged to master; better remove it."
exit 1 ;# we could allow it, but there is no point.
fi
# Is topic ever merged to next? If so you should not be rebasing it.
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git rev-list ^master ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
not_in_topic=`git rev-list "^$topic" master`
if test -z "$not_in_topic"
then
echo >&2 "$topic is already up to date with master"
exit 1 ;# we could allow it, but there is no point.
else
exit 0
fi
else
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
/usr/bin/perl -e '
my $topic = $ARGV[0];
my $msg = "* $topic has commits already merged to public branch:\n";
my (%not_in_next) = map {
/^([0-9a-f]+) /;
($1 => 1);
} split(/\n/, $ARGV[1]);
for my $elem (map {
/^([0-9a-f]+) (.*)$/;
[$1 => $2];
} split(/\n/, $ARGV[2])) {
if (!exists $not_in_next{$elem->[0]}) {
if ($msg) {
print STDERR $msg;
undef $msg;
}
print STDERR " $elem->[1]\n";
}
}
' "$topic" "$not_in_next" "$not_in_master"
exit 1
fi
<<\DOC_END
This sample hook safeguards topic branches that have been
published from being rewound.
The workflow assumed here is:
* Once a topic branch forks from "master", "master" is never
merged into it again (either directly or indirectly).
* Once a topic branch is fully cooked and merged into "master",
it is deleted. If you need to build on top of it to correct
earlier mistakes, a new topic branch is created by forking at
the tip of the "master". This is not strictly necessary, but
it makes it easier to keep your history simple.
* Whenever you need to test or publish your changes to topic
branches, merge them into "next" branch.
The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.
With this workflow, you would want to know:
(1) ... if a topic branch has ever been merged to "next". Young
topic branches can have stupid mistakes you would rather
clean up before publishing, and things that have not been
merged into other branches can be easily rebased without
affecting other people. But once it is published, you would
not want to rewind it.
(2) ... if a topic branch has been fully merged to "master".
Then you can delete it. More importantly, you should not
build on top of it -- other people may already want to
change things related to the topic as patches against your
"master", so if you need further changes, it is better to
fork the topic (perhaps with the same name) afresh from the
tip of "master".
Let's look at this example:
o---o---o---o---o---o---o---o---o---o "next"
/ / / /
/ a---a---b A / /
/ / / /
/ / c---c---c---c B /
/ / / \ /
/ / / b---b C \ /
/ / / / \ /
---o---o---o---o---o---o---o---o---o---o---o "master"
A, B and C are topic branches.
* A has one fix since it was merged up to "next".
* B has finished. It has been fully merged up to "master" and "next",
and is ready to be deleted.
* C has not merged to "next" at all.
We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.
To compute (1):
git rev-list ^master ^topic next
git rev-list ^master next
if these match, topic has not merged in next at all.
To compute (2):
git rev-list master..topic
if this is empty, it is fully merged to "master".
DOC_END

View file

@ -1,24 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to make use of push options.
# The example simply echoes all push options that start with 'echoback='
# and rejects all pushes when the "reject" push option is used.
#
# To enable this hook, rename this file to "pre-receive".
if test -n "$GIT_PUSH_OPTION_COUNT"
then
i=0
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
do
eval "value=\$GIT_PUSH_OPTION_$i"
case "$value" in
echoback=*)
echo "echo from the pre-receive-hook: ${value#*=}" >&2
;;
reject)
exit 1
esac
i=$((i + 1))
done
fi

View file

@ -1,42 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by "git commit" with the name of the file that has the
# commit message, followed by the description of the commit
# message's source. The hook's purpose is to edit the commit
# message file. If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".
# This hook includes three examples. The first one removes the
# "# Please enter the commit message..." help message.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output. It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited. This is rarely a good idea.
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
# case "$COMMIT_SOURCE,$SHA1" in
# ,|template,)
# /usr/bin/perl -i.bak -pe '
# print "\n" . `git diff --cached --name-status -r`
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
# *) ;;
# esac
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
# if test -z "$COMMIT_SOURCE"
# then
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
# fi

View file

@ -1,78 +0,0 @@
#!/usr/bin/sh
# An example hook script to update a checked-out tree on a git push.
#
# This hook is invoked by git-receive-pack(1) when it reacts to git
# push and updates reference(s) in its repository, and when the push
# tries to update the branch that is currently checked out and the
# receive.denyCurrentBranch configuration variable is set to
# updateInstead.
#
# By default, such a push is refused if the working tree and the index
# of the remote repository has any difference from the currently
# checked out commit; when both the working tree and the index match
# the current commit, they are updated to match the newly pushed tip
# of the branch. This hook is to be used to override the default
# behaviour; however the code below reimplements the default behaviour
# as a starting point for convenient modification.
#
# The hook receives the commit with which the tip of the current
# branch is going to be updated:
commit=$1
# It can exit with a non-zero status to refuse the push (when it does
# so, it must not modify the index or the working tree).
die () {
echo >&2 "$*"
exit 1
}
# Or it can make any necessary changes to the working tree and to the
# index to bring them to the desired state when the tip of the current
# branch is updated to the new commit, and exit with a zero status.
#
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
# in order to emulate git fetch that is run in the reverse direction
# with git push, as the two-tree form of git read-tree -u -m is
# essentially the same as git switch or git checkout that switches
# branches while keeping the local changes in the working tree that do
# not interfere with the difference between the branches.
# The below is a more-or-less exact translation to shell of the C code
# for the default behaviour for git's push-to-checkout hook defined in
# the push_to_deploy() function in builtin/receive-pack.c.
#
# Note that the hook will be executed from the repository directory,
# not from the working tree, so if you want to perform operations on
# the working tree, you will have to adapt your code accordingly, e.g.
# by adding "cd .." or using relative paths.
if ! git update-index -q --ignore-submodules --refresh
then
die "Up-to-date check failed"
fi
if ! git diff-files --quiet --ignore-submodules --
then
die "Working directory has unstaged changes"
fi
# This is a rough translation of:
#
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
if git cat-file -e HEAD 2>/dev/null
then
head=HEAD
else
head=$(git hash-object -t tree --stdin </dev/null)
fi
if ! git diff-index --quiet --cached --ignore-submodules $head --
then
die "Working directory has staged changes"
fi
if ! git read-tree -u -m "$commit"
then
die "Could not update working tree to new HEAD"
fi

View file

@ -1,77 +0,0 @@
#!/usr/bin/sh
# An example hook script to validate a patch (and/or patch series) before
# sending it via email.
#
# The hook should exit with non-zero status after issuing an appropriate
# message if it wants to prevent the email(s) from being sent.
#
# To enable this hook, rename this file to "sendemail-validate".
#
# By default, it will only check that the patch(es) can be applied on top of
# the default upstream branch without conflicts in a secondary worktree. After
# validation (successful or not) of the last patch of a series, the worktree
# will be deleted.
#
# The following config variables can be set to change the default remote and
# remote ref that are used to apply the patches against:
#
# sendemail.validateRemote (default: origin)
# sendemail.validateRemoteRef (default: HEAD)
#
# Replace the TODO placeholders with appropriate checks according to your
# needs.
validate_cover_letter () {
file="$1"
# TODO: Replace with appropriate checks (e.g. spell checking).
true
}
validate_patch () {
file="$1"
# Ensure that the patch applies without conflicts.
git am -3 "$file" || return
# TODO: Replace with appropriate checks for this patch
# (e.g. checkpatch.pl).
true
}
validate_series () {
# TODO: Replace with appropriate checks for the whole series
# (e.g. quick build, coding style checks, etc.).
true
}
# main -------------------------------------------------------------------------
if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
then
remote=$(git config --default origin --get sendemail.validateRemote) &&
ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
git config --replace-all sendemail.validateWorktree "$worktree"
else
worktree=$(git config --get sendemail.validateWorktree)
fi || {
echo "sendemail-validate: error: failed to prepare worktree" >&2
exit 1
}
unset GIT_DIR GIT_WORK_TREE
cd "$worktree" &&
if grep -q "^diff --git " "$1"
then
validate_patch "$1"
else
validate_cover_letter "$1"
fi &&
if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
then
git config --unset-all sendemail.validateWorktree &&
trap 'git worktree remove -ff "$worktree"' EXIT &&
validate_series
fi

View file

@ -1,128 +0,0 @@
#!/usr/bin/sh
#
# An example hook script to block unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
# This boolean sets whether unannotated tags will be allowed into the
# repository. By default they won't be.
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
# hooks.allowmodifytag
# This boolean sets whether a tag may be modified after creation. By default
# it won't be.
# hooks.allowdeletebranch
# This boolean sets whether deleting branches will be allowed in the
# repository. By default they won't be.
# hooks.denycreatebranch
# This boolean sets whether remotely creating branches will be denied
# in the repository. By default this is allowed.
#
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Config
allowunannotated=$(git config --type=bool hooks.allowunannotated)
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
;;
esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)
# un-annotated tag
short_refname=${refname##refs/tags/}
if [ "$allowunannotated" != "true" ]; then
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
exit 1
fi
;;
refs/tags/*,delete)
# delete tag
if [ "$allowdeletetag" != "true" ]; then
echo "*** Deleting a tag is not allowed in this repository" >&2
exit 1
fi
;;
refs/tags/*,tag)
# annotated tag
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' already exists." >&2
echo "*** Modifying a tag is not allowed in this repository." >&2
exit 1
fi
;;
refs/heads/*,commit)
# branch
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
echo "*** Creating a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/heads/*,delete)
# delete branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/remotes/*,commit)
# tracking branch
;;
refs/remotes/*,delete)
# delete tracking branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
exit 1
fi
;;
*)
# Anything else (is there anything else?)
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
exit 1
;;
esac
# --- Finished
exit 0

View file

@ -1,6 +0,0 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

View file

@ -1 +0,0 @@
0000000000000000000000000000000000000000 3e4bc35da41f956c873aea716c97555bf1afce5d aleidk <ale.navarro.parra@gmail.com> 1699105330 -0300 clone: from https://github.com/tmux-plugins/tmux-continuum

View file

@ -1 +0,0 @@
0000000000000000000000000000000000000000 3e4bc35da41f956c873aea716c97555bf1afce5d aleidk <ale.navarro.parra@gmail.com> 1699105330 -0300 clone: from https://github.com/tmux-plugins/tmux-continuum

View file

@ -1 +0,0 @@
0000000000000000000000000000000000000000 3e4bc35da41f956c873aea716c97555bf1afce5d aleidk <ale.navarro.parra@gmail.com> 1699105330 -0300 clone: from https://github.com/tmux-plugins/tmux-continuum

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