geomyidae

A small C-based gopherd. (gopher://bitreich.org/1/scm/geomyidae)
git clone git://r-36.net/geomyidae
Log | Files | Refs | README | LICENSE

gph-mode.el (6509B)


      1 ;;; gph-mode.el --- major mode for gph files  -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) Troels Henriksen (athas@sigkill.dk) 2022
      4 ;;
      5 ;; URL: gopher://sigkill.dk/1/programming
      6 ;; Keywords: gopher
      7 ;; Version: 1.1
      8 ;; Package-Requires: ((emacs "25.1"))
      9 
     10 ;; This file is not part of GNU Emacs.
     11 
     12 ;;; License:
     13 ;; GPL-3+
     14 
     15 ;;; Commentary:
     16 ;; .gph is the map file format used by the geomyidae Gopher daemon.
     17 ;; This Emacs mode provides basic understanding of the link syntax,
     18 ;; such that highlighting and folding works properly.  It also
     19 ;; highlights tab characters in pink because these are not allowed in
     20 ;; .gph files.
     21 ;;
     22 ;; Files with the ".gph" extension are automatically handled by this mode.
     23 ;;
     24 ;; For extensions: Define local keybindings in `gph-mode-map'.  Add
     25 ;; startup functions to `gph-mode-hook'.
     26 
     27 ;;; Code:
     28 
     29 (eval-when-compile
     30   (require 'rx))
     31 
     32 (defface gph-tabs-face
     33   '((((class color)) (:background  "hotpink"))
     34     (t (:reverse-video t)))
     35   "Face to use for highlighting tabs in Font-Lock mode.")
     36 
     37 (defvar gph-tabs 'gph-tabs-face
     38   "Face to use for highlighting tabs in Font-Lock mode.")
     39 
     40 (defvar gph--font-lock-defaults
     41   (let* ((type-rx '(or "0" "1" "3" "7" "8" "9" "g" "I" "h" "i"))
     42          (desc-rx '(* (not "|")))
     43          (path-rx '(* (not "|")))
     44          (host-rx '(* (not "|")))
     45          (port-rx '(+ digit))
     46          (link-rx `(: line-start "[" ,type-rx "|" ,desc-rx "|" ,path-rx "|" ,host-rx "|" ,port-rx "]"))
     47          (badlink-rx `(: line-start "[" (* anything))))
     48     `((,(rx-to-string link-rx) 0 font-lock-doc-markup-face)
     49       (,(rx-to-string badlink-rx) 0 font-lock-warning-face)
     50       ("\t" 0 gph-tabs))))
     51 
     52 (defvar gph-mode-hook nil
     53   "Hook for `gph-mode'.  Is run whenever the mode is entered.")
     54 
     55 (defvar gph-mode-map
     56   (let ((map (make-keymap)))
     57     map)
     58   "Keymap for `gph-mode'.")
     59 
     60 ;;;###autoload
     61 (add-to-list 'auto-mode-alist '("\\.gph" . gph-mode))
     62 
     63 ;;;###autoload
     64 (define-derived-mode gph-mode text-mode "gph"
     65   "Major mode for .gph files as used by geomyidae."
     66   (setq-local paragraph-start (concat "^\\[|\\|[ \t]*$\\|" page-delimiter))
     67   (setq-local paragraph-separate (concat "^\\[\\|[ \t]*$\\|" page-delimiter))
     68   (setq-local font-lock-defaults '(gph--font-lock-defaults)))
     69 
     70 
     71 (defun gph-insert-link (c label path server port)
     72 
     73   "Easily insert a gopher link. You will be prompted for:
     74 - C:      a character representing the link type (see list below)
     75 - LABEL:  a string to be used as the link label
     76 - PATH:   path to the item you wish to link to
     77 - SERVER: the domain of the server (defaults to 'server')
     78 - PORT:   port to use (defaults to '70')
     79 
     80 the possible options for C are:
     81   key    type           gopher equivalent
     82 - f      file           0
     83 - d      directory      1
     84 - b      binary         9
     85 - g      gif            g
     86 - I      image          I
     87 - s      search         7
     88 - h      http           h
     89 - t      telnet         8
     90 - e      error          3
     91 - i      info           i
     92 
     93 the resulting link looks something like:
     94 [0|my file|./file.txt|example.com|70]
     95 
     96 see also `gph-generate-link', which converts a gopher url to a link"
     97 
     98   (interactive "c[f]ile [d]ir [b]inary [g]if [I]mage [s]earch [h]ttp [t]elnet [e]rror [i]nfo: \nMLabel: \nMPath: \nsServer (server): \nsPort (70): ")
     99 
    100   (cond ((char-equal c ?f)
    101          (insert "[0|"))
    102         ((char-equal c ?d)
    103          (insert "[1|"))
    104         ((char-equal c ?b)
    105          (insert "[9|"))
    106         ((char-equal c ?g)
    107          (insert "[g|"))
    108         ((char-equal c ?I)
    109          (insert "[I|"))
    110         ((char-equal c ?s)
    111          (insert "[7|"))
    112         ((char-equal c ?h)
    113          (insert "[h|"))
    114         ((char-equal c ?t)
    115          (insert "[8|"))
    116         ((char-equal c ?e)
    117          (insert "[3|"))
    118         ((char-equal c ?i)
    119          (insert "[i|")))
    120   (insert (concat label "|" path "|"
    121                   (if (string-equal server "")
    122                       "server" server)
    123                   "|"
    124                   (if (string-equal port "")
    125                       "70" port)
    126                   "]")))
    127 
    128 ;; these are some functions that break up a url
    129 ;; for when automagically transforming a gopher:// url
    130 ;; into a proper geomyidae link
    131 
    132 (defun gph--remove-proto (url)
    133   "Remove 'gopher://' from a URL string."
    134    (string-trim url "gopher://" ""))
    135 
    136 (defun gph--get-domain (url)
    137   "Return only the domain name of a URL."
    138 (car (string-split (gph--remove-proto url) "/")))
    139 
    140 (defun gph--get-path (url)
    141   "Return only the resource path of the URL"
    142   (string-trim-left
    143    (string-remove-prefix (gph--get-domain url)
    144                          (gph--remove-proto url))
    145    "/[^z-a]"))
    146 
    147 (defun gph--get-type (url)
    148   "Attempt to get the link type of the  URL (like 0 for file, 1 for dir etc)."
    149   (caddr (string-split
    150           (string-remove-prefix (gph--get-domain url)
    151                                 (gph--remove-proto url))
    152           "")))
    153 
    154 (defun gph-url-to-link (url label)
    155   "Convert a gopher:// or http:// url to the geomyidae link format.
    156 this function prompts you for a URL, then for a link label. it tries to
    157 parse the URL you provide and output a correct link to that resource.
    158 
    159 The URL tries to default to whatever is in your clipboard. I don't think
    160 this works in non-graphical environments.
    161 
    162   gopher://example.com/0/some/file.txt
    163 becomes
    164   [0|my label|/some/file.txt|example.com|70]"
    165 
    166   ;; this interactive funciton is kinda big but it works okay
    167   (interactive (let* ((selection (string-truncate-left (gui-get-selection) 70))
    168                       (prompt (if (gui-get-selection)
    169                                   (format "URL (%s): "  selection)
    170                                 "URL: "))
    171                       (url (read-string prompt nil nil selection nil))
    172                       (label (read-string "Label: " nil nil nil nil)))
    173                  (list url label)))
    174 
    175   (if (or (string-prefix-p "gopher://"  url 1)
    176           (string-prefix-p "gophers://" url 1))
    177   (insert (concat
    178            "[" (gph--get-type url)
    179            "|" label
    180            "|" (gph--get-path url)
    181            "|" (gph--get-domain url)
    182            "|70]"))
    183 
    184   ;; else, it's probably an http:// link
    185   (insert (concat
    186            "[h|" label "|URL:" url "|server|70]"))))
    187 
    188 ;;gph-mode-map
    189 (define-key gph-mode-map (kbd "C-c C-,") 'gph-insert-link)
    190 (define-key gph-mode-map (kbd "C-c C-l") 'gph-url-to-link)
    191 
    192 ;; add a reminder about these bindings in the minibuffer
    193 (add-hook 'gph-mode-hook
    194           (lambda ()
    195             (message "[C-c C-,] insert link. [C-c C-l] convert URL to link. ")))
    196 
    197 (provide 'gph-mode)
    198 
    199 ;;; gph-mode.el ends here