diff options
Diffstat (limited to 'src/content/tils/2020/08')
-rw-r--r-- | src/content/tils/2020/08/12/filename-timestamp.adoc | 44 | ||||
-rw-r--r-- | src/content/tils/2020/08/13/code-jekyll.adoc | 155 | ||||
-rw-r--r-- | src/content/tils/2020/08/14/browse-git.adoc | 84 | ||||
-rw-r--r-- | src/content/tils/2020/08/16/git-search.adoc | 59 | ||||
-rw-r--r-- | src/content/tils/2020/08/28/grep-online.adoc | 139 |
5 files changed, 481 insertions, 0 deletions
diff --git a/src/content/tils/2020/08/12/filename-timestamp.adoc b/src/content/tils/2020/08/12/filename-timestamp.adoc new file mode 100644 index 0000000..7495fc9 --- /dev/null +++ b/src/content/tils/2020/08/12/filename-timestamp.adoc @@ -0,0 +1,44 @@ +--- + +title: Simple filename timestamp + +date: 2020-08-12 + +updated_at: + +layout: post + +lang: en + +ref: simple-filename-timestamp + +eu_categories: shell + +--- + +When writing Jekyll posts or creating log files with dates on them, I usually +struggle with finding a direct way of accomplishing that. There's a simple +solution: `date -I`. + +```shell +./my-program.sh > my-program.$(date -I).log +cp post-template.md _posts/$(date -I)-post-slug.md +``` + +Using this built-in GNU/Linux tool allows you to `touch $(date -I).md` to readily +create a `2020-08-12.md` file. + +I always had to read `man date` or search the web over and over, and after doing +this repeatedly it became clear that both `date -I` and `date -Is` (`s` here +stands for seconds) are the thing that I'm looking for 95% of the time: + +```shell +# inside my-program.sh +echo "Program started at $(date -Is)" +# output is: +# Program started at 2020-08-12T09:04:58-03:00 +``` + +Both date formats are hierarchical, having the bigger time intervals to the +left. This means that you can easily sort them (and even tab-complete them) with +no extra effort or tool required. diff --git a/src/content/tils/2020/08/13/code-jekyll.adoc b/src/content/tils/2020/08/13/code-jekyll.adoc new file mode 100644 index 0000000..6566928 --- /dev/null +++ b/src/content/tils/2020/08/13/code-jekyll.adoc @@ -0,0 +1,155 @@ +--- +title: Anchor headers and code lines in Jekyll +date: 2020-08-13 +layout: post +lang: en +ref: anchor-headers-and-code-lines-in-jekyll +--- +The default Jekyll toolbox ([Jekyll][0], [kramdown][1] and [rouge][2]) doesn't +provide with a configuration option to add anchors to headers and code blocks. + +[0]: https://jekyllrb.com/ +[1]: https://kramdown.gettalong.org/ +[2]: http://rouge.jneen.net/ + +The best way I found of doing this is by creating a simple Jekyll plugin, more +specifically, a [Jekyll hook][3]. These allow you to jump in to the Jekyll build +and add a processing stage before of after Jekyll performs something. + +[3]: https://jekyllrb.com/docs/plugins/hooks/ + +All you have to do is add the code to `_plugins/my-jekyll-plugin-code.rb`, and +Jekyll knows to pick it up and call your code on the appropriate time. + +## Anchor on headers + +Since I wanted to add anchors to headers in all documents, this Jekyll hook +works on `:documents` after they have been transformed into HTML, the +`:post_render` phase: + +```ruby +Jekyll::Hooks.register :documents, :post_render do |doc| + if doc.output_ext == ".html" + doc.output = + doc.output.gsub( + /<h([1-6])(.*?)id="([\w-]+)"(.*?)>(.*?)<\/h[1-6]>/, + '<a href="#\3"><h\1\2id="\3"\4>\5</h\1></a>' + ) + end +end +``` + +I've derived my implementations from two "official"[^official] hooks, +[jemoji][4] and [jekyll-mentions][5]. + +[4]: https://github.com/jekyll/jemoji +[5]: https://github.com/jekyll/jekyll-mentions +[^official]: I don't know how official they are, I just assumed it because they + live in the same organization inside GitHub that Jekyll does. + +All I did was to wrap the header tag inside an `<a>`, and set the `href` of that +`<a>` to the existing id of the header. Before the hook the HTML looks like: + +```html +...some unmodified text... +<h2 id="my-header"> + My header +</h2> +...more unmodified text... +``` + +And after the hook should turn that into: + +```html +...some unmodified text... +<a href="#my-header"> + <h2 id="my-header"> + My header + </h2> +</a> +...more unmodified text... +``` + +The used regexp tries to match only h1-h6 tags, and keep the rest of the HTML +attributes untouched, since this isn't a general HTML parser, but the generated HTML +is somewhat under your control. Use at your own risk because +[you shouldn't parse HTML with regexps][6]. Also I used this strategy in my +environment, where no other plugins are installed. I haven't considered how this +approach may conflict with other Jekyll plugins. + +[6]: https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 + +In the new anchor tag you can add your custom CSS class to style it as you wish. + +## Anchor on code blocks + +Adding anchors to code blocks needs a little bit of extra work, because line +numbers themselves don't have preexisting ids, so we need to generate them +without duplications between multiple code blocks in the same page. + +Similarly, this Jekyll hook also works on `:documents` in the `:post_render` +phase: + +```ruby +PREFIX = '<pre class="lineno">' +POSTFIX = '</pre>' +Jekyll::Hooks.register :documents, :post_render do |doc| + if doc.output_ext == ".html" + code_block_counter = 1 + doc.output = doc.output.gsub(/<pre class="lineno">[\n0-9]+<\/pre>/) do |match| + line_numbers = match + .gsub(/<pre class="lineno">([\n0-9]+)<\/pre>/, '\1') + .split("\n") + + anchored_line_numbers_array = line_numbers.map do |n| + id = "B#{code_block_counter}-L#{n}" + "<a id=\"#{id}\" href=\"##{id}\">#{n}</a>" + end + code_block_counter += 1 + + PREFIX + anchored_line_numbers_array.join("\n") + POSTFIX + end + end +end +``` + +This solution assumes the default Jekyll toolbox with code line numbers turned +on in `_config.yml`: + +```yaml +kramdown: + syntax_highlighter_opts: + span: + line_numbers: false + block: + line_numbers: true +``` + +The anchors go from B1-L1 to BN-LN, using the `code_block_counter` to track +which code block we're in and don't duplicate anchor ids. Before the hook the +HTML looks like: + +```html +...some unmodified text... +<pre class="lineno">1 +2 +3 +4 +5 +</pre> +...more unmodified text... +``` + +And after the hook should turn that into: + +```html +...some unmodified text... +<pre class="lineno"><a id="B1-L1" href="#B1-L1">1</a> +<a id="B1-L2" href="#B1-L2">2</a> +<a id="B1-L3" href="#B1-L3">3</a> +<a id="B1-L4" href="#B1-L4">4</a> +<a id="B1-L5" href="#B1-L5">5</a></pre> +...more unmodified text... +``` + +Happy writing :) diff --git a/src/content/tils/2020/08/14/browse-git.adoc b/src/content/tils/2020/08/14/browse-git.adoc new file mode 100644 index 0000000..d06f0c1 --- /dev/null +++ b/src/content/tils/2020/08/14/browse-git.adoc @@ -0,0 +1,84 @@ +--- + +title: Browse a git repository at a specific commit + +date: 2020-08-14 + +layout: post + +lang: en + +ref: browse-a-git-repository-at-a-specific-commit + +eu_categories: git + +--- + +I commonly use tools like `git log` together with `git show` when inspecting +past changes in a repository: + +```shell +git log +# search for a the commit I'm looking for +git show <my-commit> +# see the diff for the commit +``` + +But I also wanted to not only be able to look at the diff of a specific commit, +but to browse the whole repository at that specific commit. + +I used to accomplish it the "brute force" way: clone the whole repository in +another folder and checkout the commit there: + +```shell +git clone <original-repo> /tmp/tmp-repo-clone +cd /tmp-repo-clone +git checkout <my-commit> +``` + +But git itself allows we to specific the directory of the checkout by using the +`--work-tree` global git flag. This is what `man git` says about it: + +```txt +--work-tree=<path> + Set the path to the working tree. It can be an absolute path or a path relative to the current working + directory. This can also be controlled by setting the GIT_WORK_TREE environment variable and the + core.worktree configuration variable (see core.worktree in git-config(1) for a more detailed + discussion). +``` + +So it allows us to set the desired path of the working tree. So if we want to +copy the contents of the current working tree into `copy/`: + +```shell +mkdir copy +git --work-tree=copy/ checkout . +``` + +After that `copy/` will contain a replica of the code in HEAD. But to checkout a +specific, we need some extra parameters: + +```shell +git --work-tree=<dir> checkout <my-commit> -- . +``` + +There's an extra `-- .` at the end, which initially looks like we're sending +Morse signals to git, but we're actually saying to `git-checkout` which +sub directory of `<my-commit>` we want to look at. Which means we can do +something like: + +```shell +git --work-tree=<dir> checkout <my-commit> -- src/ +``` + +And with that `<dir>` will only contain what was inside `src/` at `<commit>`. + +After any of those checkouts, you have to `git reset .` to reset your current +staging area back to what it was before the checkout. + + +## References + +1. [GIT: Checkout to a specific folder][0] (StackOverflow) + +[0]: https://stackoverflow.com/a/16493707 diff --git a/src/content/tils/2020/08/16/git-search.adoc b/src/content/tils/2020/08/16/git-search.adoc new file mode 100644 index 0000000..f3ae6f0 --- /dev/null +++ b/src/content/tils/2020/08/16/git-search.adoc @@ -0,0 +1,59 @@ +--- + +title: Search in git + +date: 2020-08-16 + +layout: post + +lang: en + +ref: search-in-git + +eu_categories: git + +--- + +Here's a useful trio to know about to help you search things in git: + +1. `git show <commit>` +2. `git log --grep='<regexp>'` +3. `git grep '<regexp>' [commit]` + +## 1. `git show <commit>` + +Show a specific commit and it's diff: + +```shell +git show +# shows the latest commit +git show <commit> +# shows an specific <commit> +git show v1.2 +# shows commit tagged with v1.2 +``` + +## 2. `git log --grep='<regexp>'` + +Search through the commit messages: + +```shell +git log --grep='refactor' +``` + +## 3. `git grep '<regexp>' [commit]` + +Search content in git history: + +```shell +git grep 'TODO' +# search the repository for the "TODO" string +git grep 'TODO' $(git rev-list --all) +# search the whole history for "TODO" string +``` + +And if you find an occurrence of the regexp in a specific commit and you want to +browse the repository in that point in time, you can +[use git checkout for that][0]. + +[0]: {% link _tils/2020-08-14-browse-a-git-repository-at-a-specific-commit.md %} diff --git a/src/content/tils/2020/08/28/grep-online.adoc b/src/content/tils/2020/08/28/grep-online.adoc new file mode 100644 index 0000000..8b3b63f --- /dev/null +++ b/src/content/tils/2020/08/28/grep-online.adoc @@ -0,0 +1,139 @@ +--- + +title: Grep online repositories + +date: 2020-08-28 + +layout: post + +lang: en + +ref: grep-online-repositories + +eu_categories: git + +--- + +I often find interesting source code repositories online that I want to grep for +some pattern but I can't, because either: + +- the repository is on [cgit][cgit] or a similar code repository that doesn't + allow search in files, or; +- the search function is really bad, and doesn't allow me to use regular expressions for searching patterns in the code. + +[cgit]: https://git.zx2c4.com/cgit/ + +Here's a simple script that allows you to overcome that problem easily: + +```shell +#!/usr/bin/env bash +set -eu + +end="\033[0m" +red="\033[0;31m" +red() { echo -e "${red}${1}${end}"; } + +usage() { + red "Missing argument $1.\n" + cat <<EOF +Usage: + $0 <REGEX_PATTERN> <REPOSITORY_URL> + + Arguments: + REGEX_PATTERN Regular expression that "git grep" can search + REPOSITORY_URL URL address that "git clone" can download the repository from + +Examples: + Searching "make get-git" in cgit repository: + git search 'make get-git' https://git.zx2c4.com/cgit/ + git search 'make get-git' https://git.zx2c4.com/cgit/ -- \$(git rev-list --all) +EOF + exit 2 +} + + +REGEX_PATTERN="${1:-}" +REPOSITORY_URL="${2:-}" +[[ -z "${REGEX_PATTERN}" ]] && usage 'REGEX_PATTERN' +[[ -z "${REPOSITORY_URL}" ]] && usage 'REPOSITORY_URL' + +mkdir -p /tmp/git-search +DIRNAME="$(echo "${REPOSITORY_URL%/}" | rev | cut -d/ -f1 | rev)" +if [[ ! -d "/tmp/git-search/${DIRNAME}" ]]; then + git clone "${REPOSITORY_URL}" "/tmp/git-search/${DIRNAME}" +fi +pushd "/tmp/git-search/${DIRNAME}" + +shift 3 || shift 2 # when "--" is missing +git grep "${REGEX_PATTERN}" "${@}" +``` + +It is a wrapper around `git grep` that downloads the repository when missing. +Save in a file called `git-search`, make the file executable and add it to your +path. + +Overview: + +- *lines 1~2*: + + Bash shebang and the `set -eu` options to exit on error or undefined + variables. + +- *lines 4~30*: + + Usage text to be printed when providing less arguments than expected. + +- *line 33*: + + Extract the repository name from the URL, removing trailing slashes. + +- *lines 34~37*: + + Download the repository when missing and go to the folder. + +- *line 39*: + + Make the variable `$@` contain the rest of the unused arguments. + +- *line 40*: + + Perform `git grep`, forwarding the remaining arguments from `$@`. + +Example output: +```shell +$ git search 'make get-git' https://git.zx2c4.com/cgit/ +Clonage dans '/tmp/git-search/cgit'... +remote: Enumerating objects: 542, done. +remote: Counting objects: 100% (542/542), done. +remote: Compressing objects: 100% (101/101), done. +warning: object 51dd1eff1edc663674df9ab85d2786a40f7ae3a5: gitmodulesParse: could not parse gitmodules blob +remote: Total 7063 (delta 496), reused 446 (delta 441), pack-reused 6521 +Réception d'objets: 100% (7063/7063), 8.69 Mio | 5.39 Mio/s, fait. +Résolution des deltas: 100% (5047/5047), fait. +/tmp/git-search/cgit ~/dev/libre/songbooks/docs +README: $ make get-git + +$ git search 'make get-git' https://git.zx2c4.com/cgit/ +/tmp/git-search/cgit ~/dev/libre/songbooks/docs +README: $ make get-git +``` + +Subsequent greps on the same repository are faster because no download is needed. + +When no argument is provided, it prints the usage text: +```shell +$ git search +Missing argument REGEX_PATTERN. + +Usage: + /home/andreh/dev/libre/dotfiles/scripts/ad-hoc/git-search <REGEX_PATTERN> <REPOSITORY_URL> + + Arguments: + REGEX_PATTERN Regular expression that "git grep" can search + REPOSITORY_URL URL address that "git clone" can download the repository from + +Examples: + Searching "make get-git" in cgit repository: + git search 'make get-git' https://git.zx2c4.com/cgit/ + git search 'make get-git' https://git.zx2c4.com/cgit/ -- $(git rev-list --all) +``` |