About James Cherti

James Cherti is an experienced Infrastructure and Software engineer. He has written high-quality Python, Bash, C/C++, PHP, JavaScript source codes, administered Linux servers, and delivered several presentations in universities. He is also an active Open Source contributor.

A tool to Execute a Command in a new Tmux Window

The Python script tmux-run.py allows executing a command in a new tmux window. A tmux window is similar to a tab in other software.

If the script is executed from within a tmux session, it creates a tmux window in the same tmux session. However, if the script is executed from outside of a tmux session, it creates a new tmux window in the first available tmux session.

(Requirement: libtmux)

The Python script: tmux-run.py

#!/usr/bin/env python
# License: MIT
# Author: James Cherti
# URL: https://www.jamescherti.com/python-script-run-command-new-tmux-window/
"""Execute a command in a new tmux window.

This script allows executing a command in a new tmux window (a tmux window is
similar to a tab in other software).

- If it is executed from within a tmux session, it creates a tmux window
in the same tmux session.
- However, if the script is executed from outside of a tmux
session, it creates a new tmux window in the first available tmux session.

"""

import os
import shlex
import shutil
import sys

import libtmux


SCRIPT_NAME = os.path.basename(sys.argv[0])


def parse_args():
    if len(sys.argv) < 2:
        print(f"Usage: {SCRIPT_NAME} <command> [args...]",
              file=sys.stderr)
        sys.exit(1)

    args = sys.argv[1:]
    args[0] = shutil.which(args[0])
    if args[0] is None:
        print(f"{SCRIPT_NAME}: no {args[0]} in "
              f"({os.environ.get('PATH', '')})", file=sys.stderr)
        sys.exit(1)

    return args


def get_tmux_session():
    tmux_server = libtmux.Server()
    if not tmux_server.sessions:
        print(f"{SCRIPT_NAME}: the tmux session was not found",
              file=sys.stderr)
        sys.exit(1)

    tmux_session_id = os.environ["TMUX"].split(",")[-1]
    if tmux_session_id:
        try:
            return tmux_server.sessions.get(id=f"${tmux_session_id}")
        except Exception:  # pylint: disable=broad-except
            pass

    return tmux_server.sessions[0]


def run_in_tmux_window():
    try:
        command_args = parse_args()
        tmux_session = get_tmux_session()
        command_str = shlex.join(command_args)
        tmux_session.new_window(attach=True, window_shell=command_str)
    except libtmux.exc.LibTmuxException as err:
        print(f"Error: {err}.", file=sys.stderr)
        sys.exit(1)


if __name__ == '__main__':
    run_in_tmux_window()


Code language: Python (python)

Gentoo Linux: Unlocking a LUKS Encrypted LVM Root Partition at Boot Time using a Key File stored on an External USB Drive

Gentoo can be configured to use a key file stored on an external USB drive to unlock a LUKS encrypted LVM root partition.

We will explore in this article the general steps involved in configuring Gentoo to use an external USB drive as a key file to unlock a LUKS encrypted LVM root partition.

1. Create a key file on the USB stick and add it to the LUKS encrypted partition

Generate a key file on a mounted ext4 or vfat partition of a USB stick, which will be used by initramfs to unlock the LUKS partition:

dd if=/dev/urandom of=/PATH/TO/USBSTICK/keyfile bs=1024 count=4Code language: plaintext (plaintext)

Ensure that the partition on the USB drive has a label, as the initramfs will use this label to find where the key file is located.

Afterward, add the key file to the LUKS partition to enable decryption of the partition using that key file:

cryptsetup luksAddKey /dev/PART1 /PATH/TO/USBSTICK/keyfile

In this example, “/dev/PART1” is the partition where the LUKS encryption is enabled, and “/PATH/TO/USBSTICK/keyfile” is the location of the keyfile.

2 – Find the UUID of the encrypted partition and the label of the USB drive

Use the lsblk command to find the UUID of the encrypted partition and the label of the USB drive:

lsblk -o +UUID,LABEL

3. Configure the boot loader (such as Systemd-boot, GRUB, Syslinux…)

Add to the boot loader configuration the following initramfs kernel parameters:

  • crypt_root=UUID=A1111111-A1AA-11A1-AAAA-111AA11A1111
  • root=/dev/LVMVOLUME/root
  • root_keydev=/dev/disk/by-label/LABELNAME
  • root_key=keyfile

Here is an example for Systemd-boot:

options dolvm crypt_root=UUID=A1111111-A1AA-11A1-AAAA-111AA11A1111 root=/dev/LVMVOLUME/root root_keydev=/dev/disk/by-label/LABELNAME root_key=keyfileCode language: plaintext (plaintext)

To ensure proper setup:

  • Customize the initramfs options for LVMVOLUME, LABELNAME, and UUID=A1111111-A1AA-11A1-AAAA-111AA11A1111 to match your specific case.
  • Verify that the ext4 or vfat partition of the USB drive that is labeled “LABELNAME” contains a file named “keyfile”.
  • Make sure that the modules “dm_mod” and “usb_storage” are included in the initramfs.

This method offers a convenient way to unlock a LUKS encrypted root LVM partition. The implementation process is well-documented, making it a suitable choice for those looking to secure their Gentoo Linux systems.

How to make Vim edit/diff files from outside of Vim? (e.g. from a shell like Bash, Zsh, Fish..)

The Vim editor offers the ability to connect to a Vim server and make it perform various tasks from outside of Vim. The command-line tools vim-client-edit, vim-client-diff and the vim_client Python module, written by James Cherti, can be used to easily find and connect to a Vim server and make it perform the following tasks:

  • Edit files or directories in new tabs (The command-line tool vim-client-edit),
  • Diff/Compare up to eight files (The command-line tool vim-client-diff),
  • Evaluate expressions and return their result (The Python module vim_client),
  • Send commands and expressions to Vim (The Python module vim_client).

The command-line tools vim-client-edit and vim-client-diff are especially useful when a quick edit or comparison needs to be performed on a file from outside of Vim (e.g. from a shell like Bash, Zsh, Fish, etc.).

Additionally, the vim_client Python module allows running expressions on a Vim server and retrieving their output, which can be useful for automating tasks or scripting. For example, you can use vim-client to run a search and replace operation on a file or directory, or to perform a complex diff operation between two files.

Overall, vim-client is a powerful tool for interacting with Vim from the vim-client-edit and vim-client-diff command-line tools. The vim_client Python module can also be used to run and retrieve the output of Vim expressions, which can help automate various tasks.

Please star vim-client on GitHub to support the project!

Requirements

To use vim-client, you will need to have Vim and Python installed on your system.

Installation

The vim-client package can be installed with pip:

$ sudo pip install vim-clientCode language: Bash (bash)

Execute Vim server

The Vim editor must be started with the option “–servername”, which enables the Vim server feature that allows clients to connect and send commands to Vim:

$ vim --servername SERVERNAMECode language: plaintext (plaintext)

Make Vim server edit multiple files in tabs

Editing a list of files in new tabs:

$ vim-client-edit file1 file2 file3 

Make Vim server diff files (like vimdiff)

Comparing/diff up to eight files:

$ vim-client-diff file1 file2

Useful ~/.bashrc aliases:

Adding the following aliases to ~/.bashrc is recommended as it makes it easy to execute the command-line tools vim-client-edit and vim-client-diff:

alias gvim=vim-client-edit
alias vim=vim-client-edit
alias vi=vim-client-edit
alias vimdiff=vim-client-diff

Links related to vim-client

Vim: Edit all the files in the current directory of a Git repository in new tabs (git ls-files)

" Language: Vim script
" Description: edit all the Git files in the current
"              directory in new tabs (git ls-files
" License: MIT
" Author: James Cherti
" URL: https://www.jamescherti.com/vim-edit-git-ls-files-new-tabs/

function! GitEditFiles() abort
  if &modified
    echoerr 'fatal: No write since last change.'
    return
  endif

  let l:list_lines = systemlist('git ls-files')
  if v:shell_error !=# 0
    echomsg 'fatal: Git: ' . join(l:list_lines, "\n")
    return
  endif

  let l:list_files = []
  for l:filename in l:list_lines
    if filereadable(l:filename)
      call add(l:list_files, l:filename)
    endif
  endfor

  if len(l:list_files) ==# 0
    echo 'No Git files were found in the directory ' . getcwd()
    return
  endif

  if len(l:list_files) > 7
    for l:filename in l:list_lines
      echo l:filename
    endfor

    echo "\n"
    echo 'Git directory: ' . getcwd()
    echo 'Number of Git files: ' . len(l:list_files)
    echo "\n"
    let l:answer = input('Edit? [y,n]')
    if l:answer !=# 'y'
      return
    endif
  endif

  let l:first = 1
  for l:file in l:list_files
    if l:first
      let l:first = 0
    else
      execute 'tabnew'
    endif

    execute 'edit ' . fnameescape(l:file)
  endfor
endfunction

command! -nargs=0 GitEditFiles call GitEditFiles()Code language: Vim Script (vim)

Vim theme: tomorrow-night-deepblue, a refreshing color scheme with a deep blue background

The Vim color scheme jamescherti/vim-tomorrow-night-deepblue is a beautiful deep blue variant of the “Tomorrow Night” colorscheme, which is renowned for its elegant color palette. It is pleasing to the eyes and is easy to read (The colorscheme was previously called tomorrow-night-seablue).

The “Tomorrow Night Deepblue” color scheme features a deep blue background color that creates a calming atmosphere. The contrasting colors make it easy to distinguish between different elements of your code. The tomorrow-night-deepblue colorscheme is also a great choice for programmer who miss the blue themes that were trendy a few years ago.

The Vim theme: Tomorrow Night Deepblue

The theme was inspired by classic DOS text editors such as QuickBASIC, RHIDE, and Turbo Pascal, which featured blue backgrounds by default. There’s something special about the early days of programming and the tools we used that brings back fond memories.

Install the tomorrow-night-deepblue colorscheme with Vim’s built-in package manager (Vim 8 and above)

mkdir -p ~/.vim/pack/jamescherti/start
cd ~/.vim/pack/jamescherti/start
git clone --depth 1 https://github.com/jamescherti/vim-tomorrow-night-deepblue
vim -u NONE -c "helptags vim-tomorrow-night-deepblue/doc" -c qCode language: Bash (bash)

Activate the color scheme

:color tomorrow-night-deepblueCode language: Vim Script (vim)

Links

Bash shell: Perform tab-completion for aliases (bash-completion)

# Author: James Cherti
# License: MIT
# Requirements: bash-completion
# Description: Perform tab-completion for aliases in Bash (bash-completion).
# URL: https://www.jamescherti.com/bash-shell-perform-tab-completion-for-aliases/
#
# Add the following function to ~/.bashrc :

alias_completion() {
  local func_name='alias_completion'
  if [[ $# -lt 2 ]]; then
    echo "Usage: $func_name <cmd> <alias> <alias2> <...>" >&2
    return 1
  fi

  local cmd; cmd="$1"
  shift

  # Load the completion
  if ! type _completion_loader >/dev/null 2>&1; then
    echo "Error: $func_name: '_completion_loader' was not found." >&2
    return 1
  fi

  _completion_loader "$cmd"

  if ! complete -p "$cmd" >/dev/null; then
    echo "Error: $func_name: 'complete -p $cmd' failed." >&2
    return 1
  fi

  # Add aliases
  local alias
  for alias in "$@"; do
    complete_cmd=$(complete -p "$cmd" 2>/dev/null | sed -e 's/[[:space:]][^[:space:]]\+$//')
    complete_cmd="${complete_cmd} $alias"

    if ! ( echo "$complete_cmd" | grep -P '^\s*complete\s' >/dev/null 2>&1 ); then
      echo "Error: $func_name: alias '$alias': '$complete_cmd' is an invalid command." >&2
      return 1
    fi

    eval "$complete_cmd"
  done

  return 0
}Code language: Bash (bash)

Examples of aliases:

alias s='ssh'
alias_completion ssh s

alias g='git'
alias_completion git gCode language: Bash (bash)

Bash shell: A better version of the default bash built-in command “cd”

#!/usr/bin/env bash
# Author: James Cherti
# License: MIT
# URL: https://www.jamescherti.com/shell-bash-replacement-bash-cd-change-directory/
#
# Description:
# 1. 'cd path/to/file' will change the directory to 'path/to'
#    (the parent directory of 'file').
#
# 2. 'cd path/to/dir with spaces' will change the directory to
#    "path/to/dir with spaces".
#
# 3. 'cd file:///home/user' will change the directory to "/home/user".
# 
# 4. You can switch to the previous directory with 'popd' or 'cd -'.
#
# Add the following function and alias to ~/.bashrc :
#

_better_cd() {
  # Previous directory ('cd -')
  if [[ $# -eq 1 ]] && [[ $1 = '-' ]]; then
    popd >/dev/null || return 1
    return 0
  fi

  # Join paths
  local path
  if [[ $# -eq 0 ]]; then
    path="$HOME"
  else
    path=$(echo "$1" | sed -e 's/^file:\/\///')
    shift

    local item
    for item in "$@"; do
      path="${path} ${item}"
    done
  fi

  # Checks
  local errno=0
  if [[ -f "$path" ]]; then
    path=$(dirname "$path")
  fi

  if ! [[ -d "$path" ]]; then
    echo "$(basename "$0"):" "cd: $path: No such file or directory" >&2
    return 1
  fi

  # Change the directory
  local oldcwd; oldcwd=$(pwd)
  pushd . >/dev/null || return 1
  builtin cd "$path" >/dev/null 2>&1 || errno=1
  if [[ $oldcwd = "$(pwd)" ]]; then
    popd >/dev/null || return 1
  fi

  return "$errno"
}

alias cd=_better_cdCode language: Bash (bash)

Vim: Open documentation in a new tab for the word under the cursor (Vim help, Python, man pages, Markdown, Ansible…)

The following Vim script (VimL) function can be used to make Vim open the documentation of the word under the cursor in a new tab for various languages and tools such as Vim help (:help), Python (Pydoc), Markdown (sdcv dictionary), man pages (Vim’s built-in ‘:Man’), and Ansible (ansible-doc).

The VimL function is also extensible, meaning that you can adapt it to work with any other documentation tool. By default, the key mapping upper-case “K” can be used to open the documentation for the word under the cursor in a new tab.

" Language: Vim script
" Author: James Cherti
" License: MIT
" Description: Vim: open help/documentation in a new tab 
"              (Vim script, Python, Markdown, man pages, Ansible...).
"              Press upper-case K to open help for the word under the cursor.
" URL: https://www.jamescherti.com/vim-open-help-documentation-in-a-new-tab/

function! TabHelp(word) abort
  let l:cmd = ''

  let l:tabhelpprg = get(b:, 'tabhelpprg', '')
  if l:tabhelpprg ==# ''
    normal! K
    return
  endif

  if l:tabhelpprg[0] ==# ':'
    if stridx(l:tabhelpprg, '%s') ==# -1
      execute l:tabhelpprg
    else
      execute printf(l:tabhelpprg, fnameescape(a:word))
    endif
    return
  else
    let l:cmd = 'silent read! '
    if stridx(l:tabhelpprg, '%s') ==# -1
      let l:cmd .= l:tabhelpprg
    else
      let l:cmd .= printf(l:tabhelpprg, shellescape(a:word))
    endif
  endif

  execute 'silent tabnew help:' . fnameescape(a:word)

  setlocal modifiable
  silent normal! ggdG
  silent normal! 1Gdd
  if l:cmd !=# ''
    execute l:cmd
  endif
  silent normal! gg0
  setlocal nomodifiable
  setlocal noswapfile
  setlocal nowrap
  setlocal nonumber
  setlocal nomodified
  setlocal buftype=nofile
  setlocal bufhidden=delete
  if exists('&relativenumber')
    setlocal norelativenumber
  endif
  if exists('&signcolumn')
    setlocal signcolumn=no
  endif
  setlocal nofoldenable
  setlocal foldcolumn=0
endfunction

augroup TabHelp
  autocmd!
  autocmd FileType vim let b:tabhelpprg = ':tab help %s'
  autocmd FileType sh,zsh,csh if ! exists(':Man') | runtime ftplugin/man.vim | endif | let b:tabhelpprg = ':tab Man %s'
  autocmd FileType yaml.ansible if executable('ansible-doc') | let b:tabhelpprg = 'ansible-doc %s' | endif
  autocmd FileType markdown if executable('sdcv') | let b:tabhelpprg = 'sdcv %s' | endif
  autocmd FileType vim,sh,zsh,csh,yaml.ansible,markdown nnoremap <silent> <buffer> K :call TabHelp(expand('<cword>'))<CR>
augroup ENDCode language: Vim Script (vim)

Gentoo Linux: Printer driver for the Brother QL-1110NWB

Installing the printer driver for the Brother QL-1110NWB on Gentoo Linux can be a bit tricky, but thanks to a helpful ebuild written by James Cherti, the process becomes a breeze. The ebuild automates the whole process of downloading and installing the appropriate driver for the Brother QL-1110NWB on Gentoo Linux.

Brother QL-111NWB Driver installation on Gentoo

Create the file /etc/portage/repos.conf/motley-overlay.conf containing:

[motley-overlay]
location = /usr/local/portage/motley-overlay
sync-type = git
sync-uri = https://github.com/jamescherti/motley-overlay
priority = 9999Code language: plaintext (plaintext)

Update the repository:

emerge --sync motley-overlayCode language: plaintext (plaintext)

Install the Brother QL-1110NWB printer driver:

emerge -av net-print/brother-ql1110nwb-binCode language: plaintext (plaintext)

The ebuild will automatically download the necessary driver package from Brother and install it on your system.

Finally, restart CUPS with:

systemctl restart cupsCode language: plaintext (plaintext)

You can now register your new printer using the web interface at: http://localhost:631/

(Please add a star to the Git repository jamescherti/motley-overlay to support the project!)

Vim: Tango color scheme for Vim’s built-in Terminal

The following code snippet will allow you to apply the Tango Dark color scheme to the Vim’s built-in terminal and ensure that the terminal’s color scheme remains consistent, even if you change the Vim color scheme with the ‘:colorscheme’ command.

The snippet uses autocmd to ensures that the Vim terminal’s color scheme remains Tango Dark.

For more information about Vim’s built-in terminal:

  • :help terminal
" Language: Vim script
" Author: James Cherti
" License: MIT
" Description: Improve the color scheme of Vim Terminal (Tango dark theme),
"              and prevent :colorscheme from changing the terminal color scheme.
" URL: https://www.jamescherti.com/vim-tango-color-scheme-vim-terminal/

" Gnome-Terminal Tango Dark
let g:terminal_ansi_colors_black = '#2E3436'
let g:terminal_ansi_colors_darkred = '#CC0000'
let g:terminal_ansi_colors_darkgreen = '#4E9A06'
let g:terminal_ansi_colors_brown = '#C4A000'
let g:terminal_ansi_colors_darkblue = '#3465A4'
let g:terminal_ansi_colors_darkmagenta = '#75507B'  " dark purple
let g:terminal_ansi_colors_darkcyan = '#06989A'  " dark turquoise
let g:terminal_ansi_colors_lightgrey = '#D3D7CF'
let g:terminal_ansi_colors_darkgrey = '#555753'
let g:terminal_ansi_colors_red = '#EF2929'
let g:terminal_ansi_colors_green = '#8AE234'
let g:terminal_ansi_colors_yellow = '#FCE94F'
let g:terminal_ansi_colors_blue = '#729FCF'
let g:terminal_ansi_colors_magenta = '#AD7FA8'  " purple
let g:terminal_ansi_colors_cyan = '#34E2E2' " turquoise
let g:terminal_ansi_colors_white = '#EEEEEC'

" Text and background: Gnome dark
let g:terminal_ctermbg = 'black'
let g:terminal_ctermfg = 'white'
let g:terminal_statuslineterm_ctermbg = 'black'
let g:terminal_statuslineterm_ctermfg = 'white'
let g:terminal_statuslinetermnc_ctermbg = 'black'
let g:terminal_statuslinetermnc_ctermfg = 'white'
let g:terminal_guibg = '#000000'
let g:terminal_guifg = '#D0CFCC'
let g:terminal_statuslineterm_guibg = g:terminal_guibg
let g:terminal_statuslineterm_guifg = g:terminal_guifg
let g:terminal_statuslinetermnc_guibg = g:terminal_guibg
let g:terminal_statuslinetermnc_guifg = g:terminal_guifg

function! SetTerminalColorScheme() abort
  if !has('terminal')
    return
  endif

  let g:terminal_ansi_colors = [
        \ g:terminal_ansi_colors_black,
        \ g:terminal_ansi_colors_darkred,
        \ g:terminal_ansi_colors_darkgreen,
        \ g:terminal_ansi_colors_brown,
        \ g:terminal_ansi_colors_darkblue,
        \ g:terminal_ansi_colors_darkmagenta,
        \ g:terminal_ansi_colors_darkcyan,
        \ g:terminal_ansi_colors_lightgrey,
        \ g:terminal_ansi_colors_darkgrey,
        \ g:terminal_ansi_colors_red,
        \ g:terminal_ansi_colors_green,
        \ g:terminal_ansi_colors_yellow,
        \ g:terminal_ansi_colors_blue,
        \ g:terminal_ansi_colors_magenta,
        \ g:terminal_ansi_colors_cyan,
        \ g:terminal_ansi_colors_white
        \ ]

  execute printf(
        \ 'highlight Terminal ctermbg=%s ctermfg=%s guibg=%s guifg=%s',
        \ g:terminal_ctermbg, g:terminal_ctermfg, g:terminal_guibg,
        \ g:terminal_guifg
        \ )
  execute printf(
        \ 'highlight StatusLineTerm ctermbg=%s ctermfg=%s guibg=%s guifg=%s',
        \ g:terminal_statuslineterm_ctermbg, g:terminal_statuslineterm_ctermfg,
        \ g:terminal_statuslineterm_guibg, g:terminal_statuslineterm_guifg
        \ )
  execute printf(
        \ 'highlight StatusLineTermNC ctermbg=%s ctermfg=%s guibg=%s guifg=%s',
        \ g:terminal_statuslinetermnc_ctermbg, g:terminal_statuslinetermnc_ctermfg,
        \ g:terminal_statuslinetermnc_guibg, g:terminal_statuslinetermnc_guifg
        \ )
endfunction

if has('terminal')
  augroup TerminalColorScheme
    autocmd!
    autocmd ColorScheme * call SetTerminalColorScheme()
    autocmd VimEnter * call SetTerminalColorScheme()
  augroup END

  call SetTerminalColorScheme()
endifCode language: Vim Script (vim)

Vim: Enhance Vim tabs (file name only, file status, and the ability to rename tabs)

" Language: Vim script
" Author: James Cherti
" License: MIT
" Description: Enhance the tab line. The tabs will show the base name of 
"              the file and its status. Tabs can be renamed with 'TabRename'. 
" URL: https://www.jamescherti.com/vim-improve-the-tab-line-basename-of-the-file-and-status/

function! MyTabLabel(tabnr) abort
  let l:bufnr = tabpagebuflist(a:tabnr)[tabpagewinnr(a:tabnr) - 1]

  let l:modified = 0
  if getbufvar(l:bufnr, '&modified')
    let l:modified = 1
  endif

  let l:tablabel = ''
  let l:custom_tablabel = gettabvar(a:tabnr, 'tablabel', '')
  if empty(l:custom_tablabel)
    let l:bufname = bufname(l:bufnr)
    if empty(l:bufname)
      let l:tablabel = empty(&buftype) ? 'No Name' : '<' . &buftype . '>'
    else
      let l:tablabel = fnamemodify(l:bufname, ':t')
    endif
  else
    let l:tablabel .= l:custom_tablabel
  endif

  if l:modified
    let l:tablabel .= '*'
  endif

  return l:tablabel
endfunction

function! MyTabLine() abort
  let l:tabline = ''

  for l:num in range(1, tabpagenr('$'))
    let l:tabline .= (l:num != tabpagenr()) ? '%#TabLine#' : '%#TabLineSel#'
    let l:tabline .= '%' . l:num . 'T %{MyTabLabel(' . l:num . ')} '
  endfor

  let l:tabline .= '%#TabLineFill#%T%='
  let l:tabline .= repeat('%#TabLine#%999X[X]', l:num > 1)

  return l:tabline
endfunction

function! MyGuiTabLine() abort
  return MyTabLabel(tabpagenr())
endfunction

function! TabRename(tablabel) abort
  let t:tablabel = a:tablabel
  execute 'redrawtabline'
endfunction

if exists('+showtabline')
  command! -nargs=1 TabRename call TabRename(<q-args>)
  
  set tabline=%!MyTabLine()
  set guitablabel=%{MyGuiTabLine()}
endifCode language: Vim Script (vim)

Vim script: Replace the home directory with a tilde ~

The following Vim script (VimL) code snippet can be used to replace the full path of a home directory in a string with a tilde (“~”). This can be useful as a way to shorten the path to a file or directory, making it more readable.

" Language: Vim script
" Author: James Cherti
" License: MIT
" Description: A function that replaces the home directory 
"              with a tilde (e.g. '/home/user/file.txt' will 
"              be replaced with '~/file.txt').
" URL: https://www.jamescherti.com/vim-script-replace-the-home-directory-with-a-tilde/

function! ReplaceHomeWithTilde(path) abort
  let l:path = fnamemodify(a:path, ':p')
  let l:path_sep = (!exists('+shellslash') || &shellslash) ? '/' : '\'
  let l:home = fnamemodify('~', ':p')

  if l:path[0:len(l:home)-1] ==# l:home
    return '~' . l:path_sep . l:path[len(l:home):]
  elseif l:path == l:home
    return '~' . l:path_sep
  endif

  return l:path
endfunctionCode language: Vim Script (vim)

Python: Read the shebang line of a script

#!/usr/bin/env python
# Author: James Cherti
# License: MIT
# URL: https://www.jamescherti.com/python-read-the-shebang-line-of-a-script/
"""Read the shebang line of a script."""

import sys
import os
import shlex
from pathlib import Path
from typing import Union


class ShebangError(Exception):
    """Error with the method read_shebang()."""


def read_shebang(script_path: Union[Path, str]) -> list:
    """Return the shebang line of a file.

    >>> shebang("file.sh")
    ['/usr/bin/env', 'bash']

    """
    with open(script_path, "rb") as fhandler:
        line = fhandler.readline().strip().decode()

    if len(line) > 2 and line[0:2] == '#!':
        shebang_split = shlex.split(line[2:].strip())
        if not Path(shebang_split[0]).is_file():
            raise ShebangError(f"the shebang '{shebang_split}' does not exist")

        if not os.access(shebang_split[0], os.X_OK):
            raise ShebangError(f"the shebang '{shebang_split}' is not "
                               "executable")

        return shebang_split

    raise ShebangError("the shebang line was not found")

    
if __name__ == "__main__":
    try:
        print(read_shebang(sys.argv[1]))
    except IndexError:
        print(f"Usage: {sys.argv[0]} <file>", file=sys.stderr)
        sys.exit(1)Code language: Python (python)

Python: Calculate the size of a directory and its sub-directories

#!/usr/bin/env python
# Author: James Cherti
# License: MIT
# URL: https://www.jamescherti.com/python-calculate-the-size-of-a-directory-and-its-sub-directories/
"""Calculate the size of a directory and its sub-directories."""

import os
from pathlib import Path
from typing import Union

def get_size(path: Union[Path, str], include_dirs_size=True) -> int:
    """Return the size of a file or a directory in bytes."""
    path = Path(path)
    size = 0

    if path.is_dir():
        list_paths = path.glob("**/*")
    elif path.is_file():
        list_paths = [path]  # type: ignore
    else:
        list_paths = []  # type: ignore

    for cur_path in list_paths:
        if not include_dirs_size and cur_path.is_dir():
            continue

        if not cur_path.is_symlink():
            size += cur_path.stat().st_size

    return sizeCode language: Python (python)

A Vim function that returns all monospaced fonts (UNIX / Linux only)

" Language: Vim script
" Author: James Cherti
" License: MIT
" Description: A function that returns all available monospaced fonts 
"              (Linux and UNIX only).
" URL: https://www.jamescherti.com/vim-a-function-that-returns-all-available-fonts-unix-linux-only

function! FontList() abort
  let l:result = []

  if has('win32') || !has('gui_running') || !executable('fc-list')
    return l:result
  endif

  " Search for monospaced fonts (spacing=100)
  let l:fclist_output = systemlist('fc-list :spacing=100')
  let l:style_var = 'style='

  for l:fclist_line in l:fclist_output
    let l:fclist_line_items = split(l:fclist_line, ':')
    let l:font_file = l:fclist_line_items[0]

    let l:list_font_names = split(l:fclist_line_items[1], ',')
    let l:font_name = trim(l:list_font_names[0])

    if len(l:fclist_line_items) <= 2
      if index(l:result, l:font_name) ==# -1
        call add(l:result, l:font_name)
      endif
      continue
    endif

    let l:font_style = l:fclist_line_items[2]
    if l:font_style[0:len(l:style_var)-1] ==# l:style_var
      for l:font_style in split(l:font_style[len(l:style_var):], ',')
        let l:font_name = l:font_name . ' ' . trim(l:font_style)
        if index(l:result, l:font_name) ==# -1
          call add(l:result, l:font_name)
        endif
      endfor
    endif
  endfor

  return l:result
endfunctionCode language: Vim Script (vim)