151 lines
5.7 KiB
EmacsLisp
151 lines
5.7 KiB
EmacsLisp
;;; shrink-path.el --- fish-style path -*- lexical-binding: t; -*-
|
|
|
|
;; Copyright (C) 2017 Benjamin Andresen
|
|
|
|
;; Author: Benjamin Andresen
|
|
;; Version: 0.3.1
|
|
;; Package-Version: 20190208.1335
|
|
;; Package-Commit: c14882c8599aec79a6e8ef2d06454254bb3e1e41
|
|
;; URL: https://gitlab.com/bennya/shrink-path.el
|
|
;; Package-Requires: ((emacs "24") (s "1.6.1") (dash "1.8.0") (f "0.10.0"))
|
|
|
|
;; This file is NOT part of GNU Emacs.
|
|
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation; either version 3, or (at your option)
|
|
;; any later version.
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with GNU Emacs; see the file LICENSE. If not, write to the
|
|
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
;; Boston, MA 02110-1301, USA.
|
|
|
|
;;; Commentary:
|
|
|
|
;; Provides functions that offer fish shell[1] path truncation.
|
|
;; Directory /usr/share/emacs/site-lisp => /u/s/e/site-lisp
|
|
;;
|
|
;; Also includes utility functions that make integration in eshell or the
|
|
;; modeline easier.
|
|
;;
|
|
;; [1] https://fishshell.com/
|
|
|
|
|
|
;;; Code:
|
|
(require 'dash)
|
|
(require 's)
|
|
(require 'f)
|
|
(require 'rx)
|
|
|
|
(defun shrink-path--truncate (str)
|
|
"Return STR's first character or first two characters if hidden."
|
|
(substring str 0 (if (s-starts-with? "." str) 2 1)))
|
|
|
|
(defun shrink-path--dirs-internal (full-path &optional truncate-all)
|
|
"Return fish-style truncated string based on FULL-PATH.
|
|
Optional parameter TRUNCATE-ALL will cause the function to truncate the last
|
|
directory too."
|
|
(let* ((home (expand-file-name "~"))
|
|
(path (replace-regexp-in-string
|
|
(s-concat "^" home) "~" full-path))
|
|
(split (s-split "/" path 'omit-nulls))
|
|
(split-len (length split))
|
|
shrunk)
|
|
(->> split
|
|
(--map-indexed (if (= it-index (1- split-len))
|
|
(if truncate-all (shrink-path--truncate it) it)
|
|
(shrink-path--truncate it)))
|
|
(s-join "/")
|
|
(setq shrunk))
|
|
(s-concat (unless (s-matches? (rx bos (or "~" "/")) shrunk) "/")
|
|
shrunk
|
|
(unless (s-ends-with? "/" shrunk) "/"))))
|
|
|
|
|
|
(defun shrink-path-dirs (&optional path truncate-tail)
|
|
"Given PATH return fish-styled shrunken down path.
|
|
TRUNCATE-TAIL will cause the function to truncate the last directory too."
|
|
(let* ((path (or path default-directory))
|
|
(path (f-full path)))
|
|
(cond
|
|
((s-equals? (f-short path) "/") "/")
|
|
((s-matches? (rx bos (or "~" "/") eos) "~/"))
|
|
(t (shrink-path--dirs-internal path truncate-tail)))))
|
|
|
|
(defun shrink-path-expand (str &optional absolute-p)
|
|
"Return expanded path from STR if found or list of matches on multiple.
|
|
The path referred to by STR has to exist for this to work.
|
|
If ABSOLUTE-P is t the returned path will be absolute."
|
|
(let* ((str-split (s-split "/" str 'omit-nulls))
|
|
(head (car str-split)))
|
|
(if (= (length str-split) 1)
|
|
(s-concat "/" str-split)
|
|
(--> (-drop 1 str-split) ;; drop head
|
|
(-map (lambda (e) (s-concat e "*")) it)
|
|
(-drop-last 1 it) ;; drop tail as it may not exist
|
|
(s-join "/" it)
|
|
(s-concat (if (s-equals? head "~") "~/" head) it)
|
|
(f-glob it)
|
|
(-map (lambda (e) (s-concat e "/" (-last-item str-split))) it)
|
|
(if absolute-p (-map #'f-full it) (-map #'f-abbrev it))
|
|
(if (= (length it) 1) (car it) it)))))
|
|
|
|
(defun shrink-path-prompt (&optional pwd)
|
|
"Return cons of BASE and DIR for PWD.
|
|
If PWD isn't provided will default to `default-directory'."
|
|
(let* ((pwd (or pwd default-directory))
|
|
(shrunk (shrink-path-dirs pwd))
|
|
(split (--> shrunk (s-split "/" it 'omit-nulls)))
|
|
base dir)
|
|
(setq dir (or (-last-item split) "/"))
|
|
(setq base (if (s-equals? dir "/") ""
|
|
(s-chop-suffix (s-concat dir "/") shrunk)))
|
|
(cons base dir)))
|
|
|
|
(defun shrink-path-file (file &optional truncate-tail)
|
|
"Return FILE's shrunk down path and filename.
|
|
TRUNCATE-TAIL controls if the last directory should also be shortened."
|
|
(let ((filename (f-filename file))
|
|
(dirname (f-dirname file)))
|
|
(s-concat (shrink-path-dirs dirname truncate-tail) filename)))
|
|
|
|
(defun shrink-path-file-expand (str &optional exists-p absolute-p)
|
|
"Return STR's expanded filename.
|
|
The path referred to by STR has to exist for this to work.
|
|
If EXISTS-P is t the filename also has to exist.
|
|
If ABSOLUTE-P is t the returned path will be absolute."
|
|
(let ((expanded (shrink-path-expand str absolute-p)))
|
|
(if (and expanded exists-p)
|
|
(if (f-exists? expanded) expanded)
|
|
expanded)))
|
|
|
|
(defun shrink-path-file-mixed (shrink-path rel-path filename)
|
|
"Returns list of mixed truncated file name locations.
|
|
|
|
Consists of SHRINK-PATH's parent, SHRINK-PATH basename, relative REL-PATH and
|
|
FILENAME.
|
|
For use in modeline or prompts, etc."
|
|
(let ((shrunk-dirs (shrink-path-prompt shrink-path))
|
|
sp-parent sp-rel rel-rel nd-file)
|
|
|
|
(when (f-descendant-of? filename shrink-path)
|
|
(when shrunk-dirs
|
|
(setq sp-parent (car shrunk-dirs)
|
|
sp-rel (cdr shrunk-dirs)))
|
|
(setq rel-rel (if (or (f-same? rel-path shrink-path)
|
|
(s-equals? (f-relative rel-path shrink-path) "."))
|
|
nil
|
|
(f-relative rel-path shrink-path)))
|
|
(setq nd-file (file-name-nondirectory filename))
|
|
|
|
(list sp-parent sp-rel rel-rel nd-file))))
|
|
|
|
(provide 'shrink-path)
|
|
;;; shrink-path.el ends here
|