128 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
;;; ~/.doom.d/grid.el -*- lexical-binding: t; -*-
 | 
						|
 | 
						|
(require 's)
 | 
						|
 | 
						|
(defun grfn/all-match-groups (s)
 | 
						|
  (loop for n from 1
 | 
						|
        for x = (match-string n s)
 | 
						|
        while x
 | 
						|
        collect x))
 | 
						|
 | 
						|
(defun projectile-grid-ff (path &optional ask)
 | 
						|
  "Call `find-file' function on PATH when it is not nil and the file exists.
 | 
						|
If file does not exist and ASK in not nil it will ask user to proceed."
 | 
						|
  (if (or (and path (file-exists-p path))
 | 
						|
          (and ask (yes-or-no-p
 | 
						|
                    (s-lex-format
 | 
						|
                     "File does not exists. Create a new buffer ${path} ?"))))
 | 
						|
      (find-file path)))
 | 
						|
 | 
						|
(defun projectile-grid-goto-file (filepath &optional ask)
 | 
						|
  "Find FILEPATH after expanding root.  ASK is passed straight to `projectile-grid-ff'."
 | 
						|
  (projectile-grid-ff (projectile-expand-root filepath) ask))
 | 
						|
 | 
						|
(defun projectile-grid-choices (ds)
 | 
						|
  "Uses `projectile-dir-files' function to find files in directories.
 | 
						|
The DIRS is list of lists consisting of a directory path and regexp to filter files from that directory.
 | 
						|
Optional third element can be present in the DS list. The third element will be a prefix to be placed before
 | 
						|
the filename in the resulting choice.
 | 
						|
Returns a hash table with keys being short names (choices) and values being relative paths to the files."
 | 
						|
  (loop with hash = (make-hash-table :test 'equal)
 | 
						|
        for (dir re prefix) in ds do
 | 
						|
        (loop for file in (projectile-dir-files (projectile-expand-root dir)) do
 | 
						|
              (when (string-match re file)
 | 
						|
                (puthash
 | 
						|
                 (concat (or prefix "")
 | 
						|
                         (s-join "/" (grfn/all-match-groups file)))
 | 
						|
                 (concat dir file)
 | 
						|
                 hash)))
 | 
						|
        finally return hash))
 | 
						|
 | 
						|
(defmacro projectile-grid-find-resource (prompt dirs &optional newfile-template)
 | 
						|
  "Presents files from DIRS with PROMPT to the user using `projectile-completing-read'.
 | 
						|
If users chooses a non existant file and NEWFILE-TEMPLATE is not nil
 | 
						|
it will use that variable to interpolate the name for the new file.
 | 
						|
NEWFILE-TEMPLATE will be the argument for `s-lex-format'.
 | 
						|
The bound variable is \"filename\"."
 | 
						|
  `(lexical-let ((choices (projectile-grid-choices ,dirs)))
 | 
						|
     (projectile-completing-read
 | 
						|
      ,prompt
 | 
						|
      (hash-table-keys choices)
 | 
						|
      :action
 | 
						|
      (lambda (c)
 | 
						|
        (let* ((filepath (gethash c choices))
 | 
						|
               (filename c)) ;; so `s-lex-format' can interpolate FILENAME
 | 
						|
          (if filepath
 | 
						|
              (projectile-grid-goto-file filepath)
 | 
						|
            (when-let ((newfile-template ,newfile-template))
 | 
						|
              (projectile-grid-goto-file
 | 
						|
               (funcall newfile-template filepath)
 | 
						|
               ;; (cond
 | 
						|
               ;;  ((functionp newfile-template) (funcall newfile-template filepath))
 | 
						|
               ;;  ((stringp newfile-template) (s-lex-format newfile-template)))
 | 
						|
               t))))))))
 | 
						|
 | 
						|
(defun projectile-grid-find-model ()
 | 
						|
  "Find a model."
 | 
						|
  (interactive)
 | 
						|
  (projectile-grid-find-resource
 | 
						|
   "model: "
 | 
						|
   '(("python/urbint_lib/models/"
 | 
						|
      "\\(.+\\)\\.py$")
 | 
						|
     ("python/urbint_lib/"
 | 
						|
      "\\(.+\\)/models/\\(.+\\).py$"))
 | 
						|
   (lambda (filename)
 | 
						|
     (pcase (s-split "/" filename)
 | 
						|
       (`(,model)
 | 
						|
        (s-lex-format "python/urbint_lib/models/${model}.py"))
 | 
						|
       (`(,app ,model)
 | 
						|
        (s-lex-format "python/urbint_lib/${app}/models/${model}.py"))))))
 | 
						|
 | 
						|
(defun projectile-grid-find-repository ()
 | 
						|
  "Find a repository."
 | 
						|
  (interactive)
 | 
						|
  (projectile-grid-find-resource
 | 
						|
   "repository: "
 | 
						|
   '(("python/urbint_lib/repositories/"
 | 
						|
      "\\(.+\\)\\.py$")
 | 
						|
     ("python/urbint_lib/"
 | 
						|
      "\\(.+\\)/repositories/\\(.+\\).py$"))
 | 
						|
   (lambda (filename)
 | 
						|
     (pcase (s-split "/" filename)
 | 
						|
       (`(,repository)
 | 
						|
        (s-lex-format "python/urbint_lib/repositories/${repository}.py"))
 | 
						|
       (`(,app ,repository)
 | 
						|
        (s-lex-format "python/urbint_lib/${app}/repositories/${repository}.py"))))))
 | 
						|
 | 
						|
(defun projectile-grid-find-controller ()
 | 
						|
  "Find a controller."
 | 
						|
  (interactive)
 | 
						|
  (projectile-grid-find-resource
 | 
						|
   "controller: "
 | 
						|
   '(("backend/src/grid/api/controllers/"
 | 
						|
      "\\(.+\\)\\.py$")
 | 
						|
     ("backend/src/grid/api/apps/"
 | 
						|
      "\\(.+\\)/controllers/\\(.+\\).py$"))
 | 
						|
   (lambda (filename)
 | 
						|
     (pcase (s-split "/" filename)
 | 
						|
       (`(,controller)
 | 
						|
        (s-lex-format "backend/src/grid/api/controllers/${controller}.py"))
 | 
						|
       (`(,app ,controller)
 | 
						|
        (s-lex-format "backend/src/grid/api/apps/${app}/controllers/${controller}.py"))))))
 | 
						|
 | 
						|
(setq projectile-grid-mode-map
 | 
						|
  (let ((map (make-keymap)))
 | 
						|
    (map!
 | 
						|
     (:map map
 | 
						|
      (:leader
 | 
						|
       (:desc "Edit..." :prefix "e"
 | 
						|
        :desc "Model"      :n "m" #'projectile-grid-find-model
 | 
						|
        :desc "Controller" :n "c" #'projectile-grid-find-controller
 | 
						|
        :desc "Repository" :n "r" #'projectile-grid-find-repository))))
 | 
						|
    map))
 | 
						|
 | 
						|
(define-minor-mode projectile-grid-mode
 | 
						|
  "Minor mode for finding files in GRID"
 | 
						|
  :init-value nil
 | 
						|
  :lighter " GRID"
 | 
						|
  :keymap projectile-grid-mode-map)
 |