config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

go-playground.el (7755B)


      1 ;;; go-playground.el --- Local Golang playground for short snippets.
      2 
      3 ;; Copyright (C) 2015-2024 Alexander I.Grafov and the project
      4 ;; contibutors.
      5 
      6 ;; Author: Alexander I.Grafov <grafov@inet.name>
      7 ;; URL: https://github.com/grafov/go-playground
      8 ;; Keywords: tools, golang
      9 ;; Version: 1.8.2
     10 ;; Package-Requires: ((emacs "24") (go-mode "1.4.0") (gotest "0.13.0"))
     11 
     12 ;; This program is free software; you can redistribute it and/or modify
     13 ;; it under the terms of the GNU General Public License as published by
     14 ;; the Free Software Foundation, either version 3 of the License, or
     15 ;; (at your option) any later version.
     16 
     17 ;; This program is distributed in the hope that it will be useful,
     18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     20 ;; GNU General Public License for more details.
     21 
     22 ;; You should have received a copy of the GNU General Public License
     23 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
     24 
     25 ;;; Commentary:
     26 
     27 ;; Local playground for the Go programs similar to play.golang.org.
     28 ;; `M-x go-playground` and type you golang code then make&run it with `C-Return`.
     29 
     30 ;; Playground works around `go-mode` and requires preconfigured environment
     31 ;; for Go language.
     32 
     33 ;; I recommend you to use `goimports` instead of `gofmt` for automatically make
     34 ;; import clauses. It very comfortable especially for experimenting with code
     35 ;; in playground.
     36 
     37 ;; You may push code to play.golang.org with go-mode' function `go-play-buffer`.
     38 
     39 ;;
     40 
     41 ;;; Code:
     42 
     43 (require 'go-mode)
     44 (require 'gotest)
     45 (require 'compile)
     46 (require 'time-stamp)
     47 (require 'subr-x)
     48 
     49 (defgroup go-playground nil
     50   "Options specific to Go Playground."
     51   :group 'go)
     52 
     53 (defcustom go-playground-ask-file-name nil
     54   "Non-nil means we ask for a name for the snippet.
     55 
     56 By default it will be created as snippet.go"
     57   :type 'boolean
     58   :group 'go-playground)
     59 
     60 (defcustom go-playground-confirm-deletion t
     61   "Non-nil means you will be asked for confirmation on the snippet deletion with `go-playground-rm'.
     62 
     63 By default confirmation required."
     64   :type 'boolean
     65   :group 'go-playground)
     66 
     67 (defcustom go-playground-basedir "~/go/src/playground"
     68   "Base directory for playground snippets.  Better to set it under GOPATH."
     69   :type 'file
     70   :group 'go-playground)
     71 
     72 (defcustom go-playground-compile-command (concat go-command " mod tidy; " go-command " run ./...")
     73   "The commands used for compilation.
     74 
     75 Use \";\" or any other appropriate shell separator if you need several commands in one session."
     76   :type 'string
     77   :group 'go-playground)
     78 
     79 (defcustom go-playground-pre-rm-hook nil
     80   "Hook run before a snippet is removed."
     81   :type 'hook
     82   :group 'go-playground)
     83 
     84 (defcustom go-playground-init-command "go mod init"
     85   "The shell command executed once when the snippet just created."
     86   :type 'string
     87   :group 'go-playground)
     88 
     89 ;;;###autoload
     90 (define-minor-mode go-playground-mode
     91   "A place for playing with golang code and export it in short snippets."
     92   :init-value nil
     93   :lighter "Play(Go)"
     94   :keymap '(([C-return] . go-playground-exec)
     95 	    ([M-return] . go-playground-cmd)))
     96 
     97 (defun go-playground-snippet-file-name(&optional snippet-name)
     98   (let* ((file-name (cond (snippet-name)
     99 			 (go-playground-ask-file-name
    100 			  (read-string "Go Playground filename: "))
    101 			 ("snippet")))
    102 	 (snippet-dir (go-playground-snippet-unique-dir file-name)))
    103     (let ((default-directory snippet-dir))
    104       (call-process-shell-command go-playground-init-command))
    105     (concat snippet-dir "/" file-name ".go")))
    106 
    107 ;
    108 (defun go-playground-save-and-run ()
    109   "Obsoleted by go-playground-exec."
    110   (interactive)
    111 
    112   (go-playground-exec))
    113 
    114 (defun go-playground-exec ()
    115   "Save the buffer then runs Go compiler for executing the code."
    116   (interactive)
    117   (if (go-playground-inside)
    118 	  (progn
    119 		(save-buffer t)
    120 		(make-local-variable 'compile-command)
    121 		(compile go-playground-compile-command))))
    122 
    123 (defun go-playground-cmd (cmd)
    124   "Save the buffer then apply custom compile command from
    125 minibuffer to the files or buffer."
    126   (interactive "scompile command: ")
    127   (if (go-playground-inside)
    128 	  (progn
    129 		(save-buffer t)
    130 		(make-local-variable 'compile-command)
    131 		(compile cmd))))
    132 
    133 ;;;###autoload
    134 (defun go-playground ()
    135   "Run playground for Go language in a new buffer."
    136   (interactive)
    137   (let ((snippet-file-name (go-playground-snippet-file-name)))
    138 	(switch-to-buffer (create-file-buffer snippet-file-name))
    139 	(go-playground-insert-template-head "snippet of code")
    140 (insert "package main
    141 
    142 import (
    143 	\"fmt\"
    144 )
    145 
    146 func main() {
    147 	fmt.Println(\"Results:\")
    148 }
    149 ")
    150 	(backward-char 3)
    151 	(go-mode)
    152 	(go-playground-mode)
    153 	(set-visited-file-name snippet-file-name t)))
    154 
    155 (defun go-playground-insert-template-head (description)
    156   (insert "// -*- mode:go;mode:go-playground -*-
    157 // " description " @ " (time-stamp-string "%:y-%02m-%02d %02H:%02M:%02S") "
    158 
    159 // === Go Playground ===
    160 // Execute the snippet with:                 Ctl-Return
    161 // Provide custom arguments to compile with: Alt-Return
    162 // Other useful commands:
    163 // - remove the snippet completely with its dir and all files: (go-playground-rm)
    164 // - upload the current buffer to playground.golang.org:       (go-playground-upload)
    165 
    166 "))
    167 
    168 (defun go-playground-rm ()
    169   "Remove files of the current snippet together with directory of this snippet."
    170   (interactive)
    171   (if (go-playground-inside)
    172 	  (if (or (not go-playground-confirm-deletion)
    173 			  (y-or-n-p (format "Do you want delete whole snippet dir %s? "
    174 								(file-name-directory (buffer-file-name)))))
    175 		  (progn
    176 			(save-buffer)
    177 			(run-hooks 'go-playground-pre-rm-hook)
    178 			(delete-directory (file-name-directory (buffer-file-name)) t t)
    179 			(kill-buffer)))
    180 	(message "Won't delete this! Because %s is not under the path %s. Remove the snippet manually!"
    181 			 (buffer-file-name) go-playground-basedir)))
    182 
    183 ;;;###autoload
    184 (defun go-playground-remove-current-snippet ()
    185 	"Obsoleted by `go-playground-rm'."
    186   (interactive)
    187   (go-playground-rm))
    188 
    189 ;;;###autoload
    190 (defun go-playground-download (url)
    191   "Download a paste from the play.golang.org and insert it in a new local playground buffer.
    192 Tries to look for a URL at point."
    193   (interactive (list (read-from-minibuffer "Playground URL: " (ffap-url-p (ffap-string-at-point 'url)))))
    194   (with-current-buffer
    195 	  (let ((url-request-method "GET") url-request-data url-request-extra-headers)
    196 		(url-retrieve-synchronously (concat url ".go")))
    197 	(let* ((snippet-file-name (go-playground-snippet-file-name)) (buffer (create-file-buffer snippet-file-name)))
    198 	  (goto-char (point-min))
    199 	  (re-search-forward "\n\n")
    200 	  (copy-to-buffer buffer (point) (point-max))
    201 	  (kill-buffer)
    202 	  (with-current-buffer buffer
    203 		(goto-char (point-min))
    204 		(go-playground-insert-template-head (concat url " imported"))
    205 		(go-mode)
    206 		(go-playground-mode)
    207 		(set-visited-file-name snippet-file-name t)
    208 		(switch-to-buffer buffer)))))
    209 
    210 (defun go-playground-upload ()
    211   "Upload the current buffer to play.golang.org and return the short URL of the playground."
    212   (interactive)
    213   (if (not (go-playground-inside))
    214       (message "Not in a Go Playground buffer!")
    215     (go-play-buffer)))
    216 
    217 (defun go-playground-snippet-unique-dir (prefix)
    218   "Get unique directory under GOPATH/`go-playground-basedir`."
    219   (let ((dir-name (concat go-playground-basedir "/"
    220 						  (if (and prefix go-playground-ask-file-name) (concat prefix "-"))
    221 						  (time-stamp-string "at-%:y-%02m-%02d-%02H%02M%02S"))))
    222 	(make-directory dir-name t)
    223 	dir-name))
    224 
    225 (defun go-playground-inside ()
    226   "Is the current buffer is valid go-playground buffer."
    227   (and (bound-and-true-p go-playground-mode)
    228        buffer-file-name
    229        (string-prefix-p (file-truename go-playground-basedir)
    230 			(file-truename buffer-file-name))))
    231 
    232 (provide 'go-playground)
    233 ;;; go-playground.el ends here