;;; easy-jekyll.el --- Major mode managing jekyll blogs -*- lexical-binding: t; -*- ;; Copyright (C) 2017 by Masashı Mıyaura ;; Author: Masashı Mıyaura ;; URL: https://github.com/masasam/emacs-easy-jekyll ;; Package-Version: 1.6.13 ;; Version: 1.6.13 ;; Package-Requires: ((emacs "24.4")) ;; 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 of the License, 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 this program. If not, see . ;;; Commentary: ;; Emacs major mode for writing blogs made with jekyll ;; You can publish your blog to the server or Github Pages ;; or Amazon S3 or Google Cloud Storage. ;;; Code: (require 'cl-lib) (defgroup easy-jekyll nil "Major mode managing jekyll blogs." :group 'tools) (defgroup easy-jekyll-faces nil "Faces used in `easy-jekyll'" :group 'easy-jekyll :group 'faces) (defcustom easy-jekyll-basedir nil "Directory where jekyll html source code is placed." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-preview-url "http://localhost:4000/" "Preview url of easy-jekyll." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-url nil "Url of the site operated by jekyll." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-sshdomain nil "Domain of jekyll at your ~/.ssh/config." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-root nil "Root directory of jekyll at your server." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-previewtime 300 "Preview display time." :group 'easy-jekyll :type 'integer) (defcustom easy-jekyll-image-directory "images" "Image file directory under 'static' directory." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-default-picture-directory "~" "Default directory for selecting images with `easy-jekyll-put-image'." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-amazon-s3-bucket-name nil "Amazon S3 bucket name." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-google-cloud-storage-bucket-name nil "Google Cloud Storage bucket name." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-default-ext ".md" "Default extension when posting new articles." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-no-help nil "No help flg of easy-jekyll." :group 'easy-jekyll :type 'integer) (defcustom easy-jekyll-additional-help nil "Additional help flg of easy-jekyll." :group 'easy-jekyll :type 'integer) (defcustom easy-jekyll-sort-default-char t "Default setting to sort with charactor." :group 'easy-jekyll :type 'integer) (defcustom easy-jekyll-publish-chmod "Du=rwx,Dgo=rx,Fu=rw,Fog=r" "Permission when publish. The default is drwxr-xr-x." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-github-deploy-script "deploy.sh" "Github-deploy-script file name." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-markdown-extension "md" "Markdown extension." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-textile-extension "textile" "Textile extension." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-postdir "_posts" "Directory where stores its posts." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-rsync-delete-directory "_site/" "Disappear directory when synchronizing with rsync." :group 'easy-jekyll :type 'string) (defcustom easy-jekyll-help-line 7 "Number of lines of `easy-jekyll-help'." :group 'easy-jekyll :type 'integer) (defcustom easy-jekyll-add-help-line 5 "Number of lines of `easy-jekyll-add-help'." :group 'easy-jekyll :type 'integer) (defvar easy-jekyll--current-postdir 0 "Easy-jekyll current postdir.") (defvar easy-jekyll--postdir-list nil "Easy-jekyll postdir list.") (defvar easy-jekyll--preview-loop t "Preview loop flg.") (defvar easy-jekyll--server-process nil "Jekyll process.") (if easy-jekyll-no-help (defvar easy-jekyll--unmovable-line 3 "Impossible to move below this line.") (defvar easy-jekyll--unmovable-line (+ easy-jekyll-help-line 4) "Impossible to move below this line.")) (defvar easy-jekyll--draft-list nil "Draft list flg.") (defvar easy-jekyll--draft-mode nil "Display draft-mode.") (defconst easy-jekyll--unmovable-line-default (+ easy-jekyll-help-line 4) "Default value of impossible to move below this line.") (defconst easy-jekyll--buffer-name "*Jekyll Serve*" "Easy-jekyll buffer name.") (defconst easy-jekyll--preview-buffer "*Jekyll Preview*" "Easy-jekyll preview buffer name.") (defconst easy-jekyll--formats `(,easy-jekyll-markdown-extension ,easy-jekyll-textile-extension)) (defface easy-jekyll-help-face '((((class color) (background light)) (:inherit font-lock-function-name-face :background "#f0f8ff")) (((class color) (background dark)) (:inherit font-lock-function-name-face :background "#2f4f4f"))) "" :group 'easy-jekyll-faces) (defvar easy-jekyll--mode-buffer nil "Main buffer of easy-jekyll.") (defvar easy-jekyll--cursor nil "Cursor of easy-jekyll.") (defvar easy-jekyll--line nil "Line of easy-jekyll.") (defvar easy-jekyll--sort-time-flg nil "Sort time flg of easy-jekyll.") (defvar easy-jekyll--sort-char-flg 2 "Sort char flg of easy-jekyll.") (defvar easy-jekyll--refresh nil "Refresh flg of easy-jekyll.") (defvar easy-jekyll--current-blog 0 "Current blog number.") (defcustom easy-jekyll-bloglist nil "Multiple blog setting." :group 'easy-jekyll :type 'string) (push `((easy-jekyll-basedir . ,easy-jekyll-basedir) (easy-jekyll-url . ,easy-jekyll-url) (easy-jekyll-root . ,easy-jekyll-root) (easy-jekyll-sshdomain . ,easy-jekyll-sshdomain) (easy-jekyll-amazon-s3-bucket-name . ,easy-jekyll-amazon-s3-bucket-name) (easy-jekyll-google-cloud-storage-bucket-name . ,easy-jekyll-google-cloud-storage-bucket-name) (easy-jekyll-github-deploy-script . ,easy-jekyll-github-deploy-script) (easy-jekyll-image-directory . ,easy-jekyll-image-directory) (easy-jekyll-default-picture-directory . ,easy-jekyll-default-picture-directory) (easy-jekyll-publish-chmod . ,easy-jekyll-publish-chmod) (easy-jekyll-previewtime . ,easy-jekyll-previewtime) (easy-jekyll-preview-url . ,easy-jekyll-preview-url) (easy-jekyll-sort-default-char . ,easy-jekyll-sort-default-char) (easy-jekyll-textile-extension . ,easy-jekyll-textile-extension) (easy-jekyll-markdown-extension . ,easy-jekyll-markdown-extension) (easy-jekyll-default-ext . ,easy-jekyll-default-ext) (easy-jekyll-postdir . ,easy-jekyll-postdir)) easy-jekyll-bloglist) (defvar easy-jekyll--publish-timer-list (make-list (length easy-jekyll-bloglist) 'nil) "Timer list for cansel publish timer.") (defvar easy-jekyll--github-deploy-timer-list (make-list (length easy-jekyll-bloglist) 'nil) "Timer list for cansel github deploy timer.") (defvar easy-jekyll--amazon-s3-deploy-timer-list (make-list (length easy-jekyll-bloglist) 'nil) "Timer list for cansel amazon s3 deploy timer.") (defvar easy-jekyll--google-cloud-storage-deploy-timer-list (make-list (length easy-jekyll-bloglist) 'nil) "Timer list for cansel google cloud storage deploy timer.") (defconst easy-jekyll--default-github-deploy-script easy-jekyll-github-deploy-script "Default easy-jekyll github-deploy-script.") (defconst easy-jekyll--default-image-directory easy-jekyll-image-directory "Default easy-jekyll image-directory.") (defconst easy-jekyll--default-picture-directory easy-jekyll-default-picture-directory "Default easy-jekyll picture-directory.") (defconst easy-jekyll--default-publish-chmod easy-jekyll-publish-chmod "Default easy-jekyll publish-chmod.") (defconst easy-jekyll--default-previewtime easy-jekyll-previewtime "Default easy-jekyll previewtime.") (defconst easy-jekyll--default-preview-url easy-jekyll-preview-url "Default easy-jekyll preview-url.") (defconst easy-jekyll--default-sort-default-char easy-jekyll-sort-default-char "Default easy-jekyll sort-default-char.") (defconst easy-jekyll--default-textile-extension easy-jekyll-textile-extension "Default easy-jekyll textile-extension.") (defconst easy-jekyll--default-markdown-extension easy-jekyll-markdown-extension "Default easy-jekyll markdown-extension.") (defconst easy-jekyll--default-ext easy-jekyll-default-ext "Default easy-jekyll default-ext.") (defconst easy-jekyll--default-postdir easy-jekyll-postdir "Default easy-jekyll-postdir.") (defconst easy-jekyll--buffer-name "*Easy-jekyll*" "Buffer name of easy-jekyll.") (defconst easy-jekyll--forward-char 20 "Forward-char of easy-jekyll.") (defmacro easy-jekyll-with-env (&rest body) "Evaluate BODY with `default-directory' set to `easy-jekyll-basedir'. Report an error if jekyll is not installed, or if `easy-jekyll-basedir' is unset." `(progn (unless easy-jekyll-basedir (error "Please set easy-jekyll-basedir variable")) (unless (executable-find "jekyll") (error "'jekyll' is not installed")) (let ((default-directory easy-jekyll-basedir)) ,@body))) (defmacro easy-jekyll-set-bloglist (body) "Macros to set variables to `easy-jekyll-bloglist' as BODY." `(setq ,body (cdr (assoc ',body (nth easy-jekyll--current-blog easy-jekyll-bloglist))))) (defmacro easy-jekyll-eval-bloglist (body) "Macros to eval variables of BODY from `easy-jekyll-bloglist'." `(cdr (assoc ',body (nth easy-jekyll--current-blog easy-jekyll-bloglist)))) (defmacro easy-jekyll-nth-eval-bloglist (body blog) "Macros to eval variables of BODY from `easy-jekyll-bloglist' at BLOG." `(cdr (assoc ',body (nth ,blog easy-jekyll-bloglist)))) ;;;###autoload (defun easy-jekyll-article () "Open a list of articles written in jekyll with dired." (interactive) (unless easy-jekyll-basedir (error "Please set easy-jekyll-basedir variable")) (find-file (expand-file-name easy-jekyll-postdir easy-jekyll-basedir))) ;;;###autoload (defun easy-jekyll-magit () "Open magit at current blog." (interactive) (unless easy-jekyll-basedir (error "Please set easy-jekyll-basedir variable")) (if (package-installed-p 'magit) (magit-status-internal easy-jekyll-basedir) (error "'magit' is not installed"))) ;;;###autoload (defun easy-jekyll-image () "Generate image link." (interactive (easy-jekyll-with-env (unless (file-directory-p (expand-file-name easy-jekyll-image-directory easy-jekyll-basedir)) (error "%s does not exist" (expand-file-name easy-jekyll-image-directory easy-jekyll-basedir))) (let ((file (read-file-name "Image file: " nil (expand-file-name easy-jekyll-image-directory easy-jekyll-basedir) t (expand-file-name easy-jekyll-image-directory easy-jekyll-basedir)))) (insert (concat (format "\"\"")))))) ;;;###autoload (defun easy-jekyll-put-image () "Move image to image directory and generate image link." (interactive (easy-jekyll-with-env (unless (file-directory-p (expand-file-name easy-jekyll-image-directory easy-jekyll-basedir)) (error "%s does not exist" (expand-file-name easy-jekyll-image-directory easy-jekyll-basedir))) (let ((file (read-file-name "Image file: " nil (expand-file-name easy-jekyll-default-picture-directory) t (expand-file-name easy-jekyll-default-picture-directory)))) (copy-file file (expand-file-name (file-name-nondirectory file) easy-jekyll-image-directory)) (insert (concat (format "\"\"")))))) ;;;###autoload (defun easy-jekyll-pull-image () "Pull image from internet to image directory and generate image link." (interactive (easy-jekyll-with-env (unless (file-directory-p (expand-file-name easy-jekyll-image-directory easy-jekyll-basedir)) (error "%s does not exist" (expand-file-name easy-jekyll-image-directory easy-jekyll-basedir))) (let ((url (read-string "URL: " (if (fboundp 'gui-get-selection) (gui-get-selection)))) (file (read-file-name "Save as: " (expand-file-name easy-jekyll-image-directory easy-jekyll-basedir) (car (last (split-string (substring-no-properties (gui-get-selection)) "/"))) nil))) (when (file-exists-p (file-truename file)) (error "%s already exists!" (file-truename file))) (url-copy-file url file t) (insert (concat (format "\"\"")))))) ;;;###autoload (defun easy-jekyll-publish () "Adapt local change to the server with jekyll." (interactive) (unless easy-jekyll-sshdomain (error "Please set easy-jekyll-sshdomain variable")) (unless easy-jekyll-root (error "Please set easy-jekyll-root variable")) (unless (executable-find "rsync") (error "'rsync' is not installed")) (unless (file-exists-p "~/.ssh/config") (error "There is no ~/.ssh/config")) (easy-jekyll-with-env (when (file-directory-p "_site") (delete-directory "_site" t nil)) (let ((ret (call-process "bundle" nil "*jekyll-publish*" t "exec" "jekyll" "build" "--destination" "_site"))) (unless (zerop ret) (switch-to-buffer (get-buffer "*jekyll-publish*")) (error "'bundle exec jekyll build' command does not end normally"))) (when (get-buffer "*jekyll-publish*") (kill-buffer "*jekyll-publish*")) (shell-command-to-string (concat "rsync -rtpl --chmod=" easy-jekyll-publish-chmod " --delete " easy-jekyll-rsync-delete-directory " " easy-jekyll-sshdomain ":" (shell-quote-argument easy-jekyll-root))) (message "Blog published") (when easy-jekyll-url (browse-url easy-jekyll-url)))) ;;;###autoload (defun easy-jekyll-publish-timer (n) "A timer that publish after the specified number as N of minutes has elapsed." (interactive "nMinute:") (unless easy-jekyll-basedir (error "Please set easy-jekyll-basedir variable")) (unless (executable-find "jekyll") (error "'jekyll' is not installed")) (unless easy-jekyll-sshdomain (error "Please set easy-jekyll-sshdomain variable")) (unless easy-jekyll-root (error "Please set easy-jekyll-root variable")) (unless (executable-find "rsync") (error "'rsync' is not installed")) (unless (file-exists-p "~/.ssh/config") (error "There is no ~/.ssh/config")) (let ((blognum easy-jekyll--current-blog)) (if (nth blognum easy-jekyll--publish-timer-list) (message "There is already reserved publish-timer on %s" easy-jekyll-url) (setf (nth easy-jekyll--current-blog easy-jekyll--publish-timer-list) (run-at-time (* n 60) nil #'(lambda () (easy-jekyll-publish-on-timer blognum))))))) ;;;###autoload (defun easy-jekyll-cancel-publish-timer () "Cancel timer that publish after the specified number of minutes has elapsed." (interactive) (if (nth easy-jekyll--current-blog easy-jekyll--publish-timer-list) (progn (cancel-timer (nth easy-jekyll--current-blog easy-jekyll--publish-timer-list)) (setf (nth easy-jekyll--current-blog easy-jekyll--publish-timer-list) nil) (message "Publish-timer canceled on %s" easy-jekyll-url)) (message "There is no reserved publish-timer on %s" easy-jekyll-url))) (defun easy-jekyll-publish-on-timer (n) "Adapt local change to the server with jekyll on timer at N." (let ((default-directory (easy-jekyll-nth-eval-bloglist easy-jekyll-basedir n))) (when (file-directory-p "_site") (delete-directory "_site" t nil)) (let ((ret (call-process "bundle" nil "*jekyll-publish*" t "exec" "jekyll" "build" "--destination" "_site"))) (unless (zerop ret) (switch-to-buffer (get-buffer "*jekyll-publish*")) (setf (nth n easy-jekyll--publish-timer-list) nil) (error "'bundle exec jekyll build' command does not end normally"))) (when (get-buffer "*jekyll-publish*") (kill-buffer "*jekyll-publish*")) (shell-command-to-string (concat "rsync -rtpl --chmod=" easy-jekyll-publish-chmod " --delete " easy-jekyll-rsync-delete-directory " " (easy-jekyll-nth-eval-bloglist easy-jekyll-sshdomain n) ":" (shell-quote-argument (easy-jekyll-nth-eval-bloglist easy-jekyll-root n)))) (message "Blog published") (when (easy-jekyll-nth-eval-bloglist easy-jekyll-url n) (browse-url (easy-jekyll-nth-eval-bloglist easy-jekyll-url n))) (setf (nth n easy-jekyll--publish-timer-list) nil))) (defun easy-jekyll--headers (file) "Return a draft header string for a new article as FILE." (let ((datetimezone (concat (format-time-string "%Y-%m-%d %T ") (format-time-string "%z")))) (concat "---" "\nlayout: post" "\ntitle: " file "\ndate: " datetimezone "\n---\n"))) ;;;###autoload (defun easy-jekyll-newpost (post-file) "Create a new post with jekyll. POST-FILE needs to have and extension '.md' or '.textile'." (interactive (list (read-from-minibuffer "Filename: " `(,easy-jekyll-default-ext . 1) nil nil nil))) (easy-jekyll-with-env (let ((filename (if easy-jekyll--draft-list (expand-file-name post-file "_drafts") (expand-file-name (concat (format-time-string "%Y-%m-%d-" (current-time)) post-file) easy-jekyll-postdir))) (file-ext (file-name-extension post-file))) (when (not (member file-ext easy-jekyll--formats)) (error "Please enter .%s file name or .%s file name" easy-jekyll-markdown-extension easy-jekyll-textile-extension)) (when (file-exists-p (file-truename filename)) (error "%s already exists!" filename)) (find-file filename) (insert (easy-jekyll--headers (file-name-base post-file))) (goto-char (point-max)) (save-buffer)))) (defun easy-jekyll--version () "Return the version of jekyll." (let ((source (split-string (with-temp-buffer (shell-command-to-string "bundle exec jekyll --version")) " "))) (string-to-number (nth 1 source)))) ;;;###autoload (defun easy-jekyll-preview () "Preview jekyll at localhost." (interactive) (easy-jekyll-with-env (if (process-live-p easy-jekyll--server-process) (browse-url easy-jekyll-preview-url) (progn (setq easy-jekyll--server-process (start-process "jekyll-serve" easy-jekyll--preview-buffer "bundle" "exec" "jekyll" "serve")) (while easy-jekyll--preview-loop (if (equal (easy-jekyll--preview-status) "200") (progn (setq easy-jekyll--preview-loop nil) (browse-url easy-jekyll-preview-url))) (sleep-for 0 100) (if (and (eq (process-status easy-jekyll--server-process) 'exit) (not (equal (process-exit-status easy-jekyll--server-process) 0))) (progn (switch-to-buffer easy-jekyll--preview-buffer) (error "Jekyll error look at %s buffer" easy-jekyll--preview-buffer)))) (setq easy-jekyll--preview-loop t) (run-at-time easy-jekyll-previewtime nil 'easy-jekyll--preview-end))))) (defun easy-jekyll--preview-status () "Return the http status code of the preview." (nth 1 (split-string (nth 0 (split-string (with-current-buffer (easy-jekyll--url-retrieve-synchronously "http://127.0.0.1:4000/") (prog1 (buffer-string) (kill-buffer))) "\n")) " "))) (defun easy-jekyll--url-retrieve-synchronously (url &optional silent inhibit-cookies) "Retrieve URL synchronously. Return the buffer containing the data, or nil if there are no data associated with it (the case for dired, info, or mailto URLs that need no further processing). URL is either a string or a parsed URL. If SILENT is non-nil, don't display progress reports and similar messages. If INHIBIT-COOKIES is non-nil, cookies will neither be stored nor sent to the server." (url-do-setup) (let ((retrieval-done nil) (asynch-buffer nil)) (setq asynch-buffer (url-retrieve url (lambda (&rest ignored) (url-debug 'retrieval "Synchronous fetching done (%S)" (current-buffer)) (setq retrieval-done t asynch-buffer (current-buffer))) nil silent inhibit-cookies)) (if (null asynch-buffer) ;; We do not need to do anything, it was a mailto or something ;; similar that takes processing completely outside of the URL ;; package. nil (let ((proc (get-buffer-process asynch-buffer))) ;; If the access method was synchronous, `retrieval-done' should ;; hopefully already be set to t. If it is nil, and `proc' is also ;; nil, it implies that the async process is not running in ;; asynch-buffer. This happens e.g. for FTP files. In such a case ;; url-file.el should probably set something like a `url-process' ;; buffer-local variable so we can find the exact process that we ;; should be waiting for. In the mean time, we'll just wait for any ;; process output. (while (not retrieval-done) (url-debug 'retrieval "Spinning in url-retrieve-synchronously: %S (%S)" retrieval-done asynch-buffer) (if (buffer-local-value 'url-redirect-buffer asynch-buffer) (setq proc (get-buffer-process (setq asynch-buffer (buffer-local-value 'url-redirect-buffer asynch-buffer)))) (if (and proc (memq (process-status proc) '(closed exit signal failed)) ;; Make sure another process hasn't been started. (eq proc (or (get-buffer-process asynch-buffer) proc))) ;; FIXME: It's not clear whether url-retrieve's callback is ;; guaranteed to be called or not. It seems that url-http ;; decides sometimes consciously not to call it, so it's not ;; clear that it's a bug, but even then we need to decide how ;; url-http can then warn us that the download has completed. ;; In the mean time, we use this here workaround. ;; XXX: The callback must always be called. Any ;; exception is a bug that should be fixed, not worked ;; around. (progn ;; Call delete-process so we run any sentinel now. (delete-process proc) (setq retrieval-done t))) ;; We used to use `sit-for' here, but in some cases it wouldn't ;; work because apparently pending keyboard input would always ;; interrupt it before it got a chance to handle process input. ;; `sleep-for' was tried but it lead to other forms of ;; hanging. --Stef (unless (or (with-local-quit (accept-process-output proc)) (null proc)) ;; accept-process-output returned nil, maybe because the process ;; exited (and may have been replaced with another). If we got ;; a quit, just stop. (when quit-flag (delete-process proc)) (setq proc (and (not quit-flag) (get-buffer-process asynch-buffer))))))) asynch-buffer))) (defun easy-jekyll--preview-end () "Finish previewing jekyll at localhost." (unless (null easy-jekyll--server-process) (delete-process easy-jekyll--server-process)) (when (get-buffer easy-jekyll--preview-buffer) (kill-buffer easy-jekyll--preview-buffer))) ;;;###autoload (defun easy-jekyll-github-deploy () "Execute `easy-jekyll-github-deploy-script' script locate at `easy-jekyll-basedir'." (interactive) (easy-jekyll-with-env (let ((deployscript (file-truename (expand-file-name easy-jekyll-github-deploy-script easy-jekyll-basedir)))) (unless (executable-find deployscript) (error "%s do not execute" deployscript)) (let ((ret (call-process (shell-quote-argument deployscript) nil "*jekyll-github-deploy*" t))) (unless (zerop ret) (switch-to-buffer (get-buffer "*jekyll-github-deploy*")) (error "%s command does not end normally" deployscript))) (when (get-buffer "*jekyll-github-deploy*") (kill-buffer "*jekyll-github-deploy*")) (message "Blog deployed") (when easy-jekyll-url (browse-url easy-jekyll-url))))) ;;;###autoload (defun easy-jekyll-github-deploy-timer (n) "A timer that github-deploy after the specified number as N of minutes has elapsed." (interactive "nMinute:") (unless easy-jekyll-basedir (error "Please set easy-jekyll-basedir variable")) (unless (executable-find "jekyll") (error "'jekyll' is not installed")) (let ((deployscript (file-truename (expand-file-name easy-jekyll-github-deploy-script easy-jekyll-basedir))) (blognum easy-jekyll--current-blog)) (unless (executable-find deployscript) (error "%s do not execute" deployscript)) (if (nth blognum easy-jekyll--github-deploy-timer-list) (message "There is already reserved github-deloy-timer on %s" easy-jekyll-url) (setf (nth easy-jekyll--current-blog easy-jekyll--github-deploy-timer-list) (run-at-time (* n 60) nil #'(lambda () (easy-jekyll-github-deploy-on-timer blognum))))))) ;;;###autoload (defun easy-jekyll-cancel-github-deploy-timer () "Cancel timer that github-deploy after the specified number of minutes has elapsed." (interactive) (if (nth easy-jekyll--current-blog easy-jekyll--github-deploy-timer-list) (progn (cancel-timer (nth easy-jekyll--current-blog easy-jekyll--github-deploy-timer-list)) (setf (nth easy-jekyll--current-blog easy-jekyll--github-deploy-timer-list) nil) (message "Github-deploy-timer canceled on %s" easy-jekyll-url)) (message "There is no reserved github-deploy-timer on %s" easy-jekyll-url))) (defun easy-jekyll-github-deploy-on-timer (n) "Execute `easy-jekyll-github-deploy-script' script on timer locate at `easy-jekyll-basedir' at N." (let* ((deployscript (file-truename (expand-file-name (if (easy-jekyll-nth-eval-bloglist easy-jekyll-github-deploy-script n) (easy-jekyll-nth-eval-bloglist easy-jekyll-github-deploy-script n) easy-jekyll--default-github-deploy-script) (easy-jekyll-nth-eval-bloglist easy-jekyll-basedir n)))) (default-directory (easy-jekyll-nth-eval-bloglist easy-jekyll-basedir n)) (ret (call-process (shell-quote-argument deployscript) nil "*jekyll-github-deploy*" t)) (default-directory easy-jekyll-basedir)) (unless (zerop ret) (switch-to-buffer (get-buffer "*jekyll-github-deploy*")) (setf (nth n easy-jekyll--github-deploy-timer-list) nil) (error "%s command does not end normally" deployscript))) (when (get-buffer "*jekyll-github-deploy*") (kill-buffer "*jekyll-github-deploy*")) (message "Blog deployed") (when (easy-jekyll-nth-eval-bloglist easy-jekyll-url n) (browse-url (easy-jekyll-nth-eval-bloglist easy-jekyll-url n))) (setf (nth n easy-jekyll--github-deploy-timer-list) nil)) ;;;###autoload (defun easy-jekyll-amazon-s3-deploy () "Deploy jekyll source at Amazon S3." (interactive) (easy-jekyll-with-env (unless (executable-find "aws") (error "'aws' is not installed")) (unless easy-jekyll-amazon-s3-bucket-name (error "Please set 'easy-jekyll-amazon-s3-bucket-name' variable")) (when (file-directory-p "_site") (delete-directory "_site" t nil)) (let ((ret (call-process "bundle" nil "*jekyll-amazon-s3-deploy*" t "exec" "jekyll" "build" "--destination" "_site"))) (unless (zerop ret) (switch-to-buffer (get-buffer "*jekyll-amazon-s3-deploy*")) (error "'bundle exec jekyll build' command does not end normally"))) (when (get-buffer "*jekyll-amazon-s3-deploy*") (kill-buffer "*jekyll-amazon-s3-deploy*")) (shell-command-to-string (concat "aws s3 sync --delete _site s3://" easy-jekyll-amazon-s3-bucket-name "/")) (message "Blog deployed") (when easy-jekyll-url (browse-url easy-jekyll-url)))) ;;;###autoload (defun easy-jekyll-amazon-s3-deploy-timer (n) "A timer that amazon-s3-deploy after the specified number as N of minutes has elapsed." (interactive "nMinute:") (unless easy-jekyll-basedir (error "Please set easy-jekyll-basedir variable")) (unless (executable-find "jekyll") (error "'jekyll' is not installed")) (unless (executable-find "aws") (error "'aws' is not installed")) (unless easy-jekyll-amazon-s3-bucket-name (error "Please set 'easy-jekyll-amazon-s3-bucket-name' variable")) (let ((blognum easy-jekyll--current-blog)) (if (nth blognum easy-jekyll--amazon-s3-deploy-timer-list) (message "There is already reserved AWS-s3-deploy-timer on %s" easy-jekyll-url) (setf (nth easy-jekyll--current-blog easy-jekyll--amazon-s3-deploy-timer-list) (run-at-time (* n 60) nil #'(lambda () (easy-jekyll-amazon-s3-deploy-on-timer blognum))))))) ;;;###autoload (defun easy-jekyll-cancel-amazon-s3-deploy-timer () "Cancel timer that amazon-s3-deploy after the specified number of minutes has elapsed." (interactive) (if (nth easy-jekyll--current-blog easy-jekyll--amazon-s3-deploy-timer-list) (progn (cancel-timer (nth easy-jekyll--current-blog easy-jekyll--amazon-s3-deploy-timer-list)) (setf (nth easy-jekyll--current-blog easy-jekyll--amazon-s3-deploy-timer-list) nil) (message "AWS-s3-deploy-timer canceled on %s" easy-jekyll-url)) (message "There is no reserved AWS-s3-deploy-timer on %s" easy-jekyll-url))) (defun easy-jekyll-amazon-s3-deploy-on-timer (n) "Deploy jekyll source at Amazon S3 on timer at N." (let* ((default-directory (easy-jekyll-nth-eval-bloglist easy-jekyll-basedir n)) (ret (call-process "bundle" nil "*jekyll-amazon-s3-deploy*" t "exec" "jekyll" "build" "--destination" "_site")) (default-directory easy-jekyll-basedir)) (unless (zerop ret) (switch-to-buffer (get-buffer "*jekyll-amazon-s3-deploy*")) (setf (nth n easy-jekyll--amazon-s3-deploy-timer-list) nil) (error "'bundle exec jekyll build' command does not end normally"))) (when (get-buffer "*jekyll-amazon-s3-deploy*") (kill-buffer "*jekyll-amazon-s3-deploy*")) (setq default-directory (easy-jekyll-nth-eval-bloglist easy-jekyll-basedir n)) (shell-command-to-string (concat "aws s3 sync --delete _site s3://" easy-jekyll-amazon-s3-bucket-name "/")) (setq default-directory easy-jekyll-basedir) (message "Blog deployed") (when (easy-jekyll-nth-eval-bloglist easy-jekyll-url n) (browse-url (easy-jekyll-nth-eval-bloglist easy-jekyll-url n))) (setf (nth n easy-jekyll--amazon-s3-deploy-timer-list) nil)) ;;;###autoload (defun easy-jekyll-google-cloud-storage-deploy () "Deploy jekyll source at Google Cloud Storage." (interactive) (easy-jekyll-with-env (unless (executable-find "gsutil") (error "'Google Cloud SDK' is not installed")) (unless easy-jekyll-google-cloud-storage-bucket-name (error "Please set 'easy-jekyll-google-cloud-storage-bucket-name' variable")) (when (file-directory-p "_site") (delete-directory "_site" t nil)) (let ((ret (call-process "bundle" nil "*jekyll-google-cloud-storage-deploy*" t "exec" "jekyll" "build" "--destination" "_site"))) (unless (zerop ret) (switch-to-buffer (get-buffer "*jekyll-google-cloud-storage-deploy*")) (error "'bundle exec jekyll build' command does not end normally"))) (when (get-buffer "*jekyll-google-cloud-storage-deploy*") (kill-buffer "*jekyll-google-cloud-storage-deploy*")) (shell-command-to-string (concat "gsutil -m rsync -d -r _site gs://" easy-jekyll-google-cloud-storage-bucket-name "/")) (message "Blog deployed") (when easy-jekyll-url (browse-url easy-jekyll-url)))) ;;;###autoload (defun easy-jekyll-google-cloud-storage-deploy-timer (n) "A timer that google-cloud-storage-deploy after the specified number as N of minutes has elapsed." (interactive "nMinute:") (unless easy-jekyll-basedir (error "Please set easy-jekyll-basedir variable")) (unless (executable-find "jekyll") (error "'jekyll' is not installed")) (unless (executable-find "gsutil") (error "'Google Cloud SDK' is not installed")) (unless easy-jekyll-google-cloud-storage-bucket-name (error "Please set 'easy-jekyll-google-cloud-storage-bucket-name' variable")) (let ((blognum easy-jekyll--current-blog)) (if (nth blognum easy-jekyll--google-cloud-storage-deploy-timer-list) (message "There is already reserved google-cloud-storage-deploy-timer on %s" easy-jekyll-url) (setf (nth easy-jekyll--current-blog easy-jekyll--google-cloud-storage-deploy-timer-list) (run-at-time (* n 60) nil #'(lambda () (easy-jekyll-google-cloud-storage-deploy-on-timer blognum))))))) ;;;###autoload (defun easy-jekyll-cancel-google-cloud-storage-deploy-timer () "Cancel timer that google-cloud-storage-deploy after the specified number of minutes has elapsed." (interactive) (if (nth easy-jekyll--current-blog easy-jekyll--google-cloud-storage-deploy-timer-list) (progn (cancel-timer (nth easy-jekyll--current-blog easy-jekyll--google-cloud-storage-deploy-timer-list)) (setf (nth easy-jekyll--current-blog easy-jekyll--google-cloud-storage-deploy-timer-list) nil) (message "GCS-timer canceled on %s" easy-jekyll-url)) (message "There is no reserved GCS-timer on %s" easy-jekyll-url))) (defun easy-jekyll-google-cloud-storage-deploy-on-timer (n) "Deploy jekyll source at Google Cloud Storage on timer at N." (let* ((default-directory (easy-jekyll-nth-eval-bloglist easy-jekyll-basedir n)) (ret (call-process "bundle" nil "*jekyll-google-cloud-storage-deploy*" t "exec" "jekyll" "build" "--destination" "_site")) (default-directory easy-jekyll-basedir)) (unless (zerop ret) (switch-to-buffer (get-buffer "*jekyll-google-cloud-storage-deploy*")) (setf (nth n easy-jekyll--google-cloud-storage-deploy-timer-list) nil) (error "'bundle exec jekyll build' command does not end normally"))) (when (get-buffer "*jekyll-google-cloud-storage-deploy*") (kill-buffer "*jekyll-google-cloud-storage-deploy*")) (setq default-directory (easy-jekyll-nth-eval-bloglist easy-jekyll-basedir n)) (shell-command-to-string (concat "gsutil -m rsync -d -r _site gs://" (easy-jekyll-nth-eval-bloglist easy-jekyll-google-cloud-storage-bucket-name n) "/")) (setq default-directory easy-jekyll-basedir) (message "Blog deployed") (when (easy-jekyll-nth-eval-bloglist easy-jekyll-url n) (browse-url (easy-jekyll-nth-eval-bloglist easy-jekyll-url n))) (setf (nth n easy-jekyll--google-cloud-storage-deploy-timer-list) nil)) ;;;###autoload (defun easy-jekyll-ag () "Search for blog article with counsel-ag or helm-ag." (interactive) (easy-jekyll-with-env (if (package-installed-p 'counsel) (counsel-ag nil (expand-file-name easy-jekyll-postdir easy-jekyll-basedir)) (if (package-installed-p 'helm-ag) (helm-ag (expand-file-name easy-jekyll-postdir easy-jekyll-basedir)) (error "'counsel' or 'helm-ag' is not installed"))))) ;;;###autoload (defun easy-jekyll-open-config () "Open Jekyll's config file." (interactive) (easy-jekyll-with-env (cond ((file-exists-p (expand-file-name "_config.yml" easy-jekyll-basedir)) (find-file (expand-file-name "_config.yml" easy-jekyll-basedir))) (t (error "Jekyll config file not found at %s" easy-jekyll-basedir))))) (defcustom easy-jekyll-help (if (null easy-jekyll-sort-default-char) (progn "n .. New blog post R .. Rename file G .. Deploy GitHub ? .. Help easy-jekyll p .. Preview g .. Refresh A .. Deploy AWS S3 u .. Undraft file v .. Open view-mode s .. Sort time T .. Publish timer W .. AWS S3 timer d .. Delete post c .. Open config D .. Draft list I .. GCS timer P .. Publish server C .. Deploy GCS a .. Search blog ag H .. GitHub timer < .. Previous blog > .. Next blog , .. Pre postdir . .. Next postdir F .. Full help [tab] M .. Magit status ? .. Describe-mode q .. Quit easy-jekyll ") (progn "n .. New blog post R .. Rename file G .. Deploy GitHub N .. No help-mode p .. Preview g .. Refresh A .. Deploy AWS S3 s .. Sort character v .. Open view-mode D .. Draft list T .. Publish timer M .. Magit status d .. Delete post c .. Open config u .. Undraft file I .. GCS timer P .. Publish server C .. Deploy GCS a .. Search blog ag H .. GitHub timer < .. Previous blog > .. Next blog , .. Pre postdir . .. Next postdir F .. Full help [tab] W .. AWS S3 timer ? .. Describe-mode q .. Quit easy-jekyll ")) "Help of easy-jekyll." :group 'easy-jekyll :type 'string) (defconst easy-jekyll--first-help "Welcome to Easy-jekyll Let's post an article first. Press n on this screen or M-x easy-jekyll-newpost. Enter a article file name in the minibuffer. Then M-x easy-jekyll again or refresh the screen with r or g key in this buffer, article which you wrote should appear here. Enjoy! " "Help of easy-jekyll first time.") (defcustom easy-jekyll-add-help (if (null easy-jekyll-sort-default-char) (progn "O .. Open basedir r .. Refresh b .. X github timer t .. X publish-timer k .. Previous-line j .. Next line h .. backward-char l .. forward-char m .. X s3-timer i .. X GCS timer f .. File open V .. View other window - .. Pre postdir + .. Next postdir w .. Write post o .. Open other window J .. Jump blog e .. Edit file S .. Sort char ") (progn "O .. Open basedir r .. Refresh b .. X github timer t .. X publish-timer k .. Previous-line j .. Next line h .. backward-char l .. forward-char m .. X s3-timer i .. X GCS timer f .. File open V .. View other window - .. Pre postdir + .. Next postdir w .. Write post o .. Open other window J .. Jump blog e .. Edit file S .. Sort time ")) "Add help of easy-jekyll." :group 'easy-jekyll :type 'string) (defvar easy-jekyll-mode-map (let ((map (make-keymap))) (define-key map "." 'easy-jekyll-next-postdir) (define-key map "," 'easy-jekyll-previous-postdir) (define-key map "+" 'easy-jekyll-next-postdir) (define-key map "-" 'easy-jekyll-previous-postdir) (define-key map "n" 'easy-jekyll-newpost) (define-key map "w" 'easy-jekyll-newpost) (define-key map "a" 'easy-jekyll-ag) (define-key map "M" 'easy-jekyll-magit) (define-key map "c" 'easy-jekyll-open-config) (define-key map "p" 'easy-jekyll-preview) (define-key map "P" 'easy-jekyll-publish) (define-key map "T" 'easy-jekyll-publish-timer) (define-key map "W" 'easy-jekyll-amazon-s3-deploy-timer) (define-key map "t" 'easy-jekyll-cancel-publish-timer) (define-key map "o" 'easy-jekyll-open-other-window) (define-key map "O" 'easy-jekyll-open-basedir) (define-key map "R" 'easy-jekyll-rename) (define-key map "\C-m" 'easy-jekyll-open) (put 'easy-jekyll-open :advertised-binding "\C-m") (define-key map "d" 'easy-jekyll-delete) (define-key map "e" 'easy-jekyll-open) (define-key map "f" 'easy-jekyll-open) (define-key map "F" 'easy-jekyll-full-help) (define-key map [tab] 'easy-jekyll-full-help) (define-key map [backtab] 'easy-jekyll-no-help) (define-key map "N" 'easy-jekyll-no-help) (define-key map "J" 'easy-jekyll-nth-blog) (define-key map "j" 'easy-jekyll-next-line) (define-key map "k" 'easy-jekyll-previous-line) (define-key map "h" 'easy-jekyll-backward-char) (define-key map "l" 'easy-jekyll-forward-char) (define-key map " " 'easy-jekyll-next-line) (define-key map [?\S-\ ] 'easy-jekyll-previous-line) (define-key map [remap next-line] 'easy-jekyll-next-line) (define-key map [remap previous-line] 'easy-jekyll-previous-line) (define-key map [remap forward-char] 'easy-jekyll-forward-char) (define-key map [remap backward-char] 'easy-jekyll-backward-char) (define-key map [remap beginning-of-buffer] 'easy-jekyll-beginning-of-buffer) (define-key map [remap backward-word] 'easy-jekyll-backward-word) (define-key map [right] 'easy-jekyll-forward-char) (define-key map [left] 'easy-jekyll-backward-char) (define-key map "v" 'easy-jekyll-view) (define-key map "V" 'easy-jekyll-view-other-window) (define-key map "r" 'easy-jekyll-refresh) (define-key map "g" 'easy-jekyll-refresh) (if (null easy-jekyll-sort-default-char) (progn (define-key map "s" 'easy-jekyll-sort-time) (define-key map "S" 'easy-jekyll-sort-char)) (progn (define-key map "S" 'easy-jekyll-sort-time) (define-key map "s" 'easy-jekyll-sort-char))) (define-key map "G" 'easy-jekyll-github-deploy) (define-key map "H" 'easy-jekyll-github-deploy-timer) (define-key map "b" 'easy-jekyll-cancel-github-deploy-timer) (define-key map "A" 'easy-jekyll-amazon-s3-deploy) (define-key map "m" 'easy-jekyll-cancel-amazon-s3-deploy-timer) (define-key map "C" 'easy-jekyll-google-cloud-storage-deploy) (define-key map "I" 'easy-jekyll-google-cloud-storage-deploy-timer) (define-key map "i" 'easy-jekyll-cancel-google-cloud-storage-deploy-timer) (define-key map "D" 'easy-jekyll-list-draft) (define-key map "u" 'easy-jekyll-undraft) (define-key map "q" 'easy-jekyll-quit) (define-key map "<" 'easy-jekyll-previous-blog) (define-key map ">" 'easy-jekyll-next-blog) map) "Keymap for easy-jekyll major mode.") (define-derived-mode easy-jekyll-mode special-mode "Easy-jekyll" "Major mode for easy jekyll.") (defun easy-jekyll-quit () "Quit easy jekyll." (interactive) (setq easy-jekyll--sort-time-flg nil) (setq easy-jekyll--sort-char-flg 2) (easy-jekyll--preview-end) (when (buffer-live-p easy-jekyll--mode-buffer) (kill-buffer easy-jekyll--mode-buffer))) (defun easy-jekyll-no-help () "No help easy jekyll." (interactive) (if easy-jekyll-no-help (progn (setq easy-jekyll-no-help nil) (setq easy-jekyll--unmovable-line easy-jekyll--unmovable-line-default)) (progn (setq easy-jekyll-no-help 1) (setq easy-jekyll-additional-help nil) (setq easy-jekyll--unmovable-line 3))) (if easy-jekyll--draft-list (easy-jekyll-draft-list) (easy-jekyll))) (defun easy-jekyll-full-help () "Full help mode of easy jekyll." (interactive) (if easy-jekyll-additional-help (progn (setq easy-jekyll-additional-help nil) (setq easy-jekyll--unmovable-line easy-jekyll--unmovable-line-default)) (progn (setq easy-jekyll-additional-help 1) (setq easy-jekyll-no-help nil) (setq easy-jekyll--unmovable-line (+ easy-jekyll-help-line easy-jekyll-add-help-line 4)))) (if easy-jekyll--draft-list (easy-jekyll-draft-list) (easy-jekyll))) (defun easy-jekyll-list-draft () "List drafts." (interactive) (if easy-jekyll--draft-list (progn (setq easy-jekyll--draft-list nil) (setq easy-jekyll--draft-mode nil) (easy-jekyll)) (progn (setq easy-jekyll--draft-list 1) (setq easy-jekyll--draft-mode " Draft") (easy-jekyll-draft-list)))) (defun easy-jekyll-refresh () "Refresh easy-jekyll-mode." (interactive) (setq easy-jekyll--cursor (point)) (setq easy-jekyll--refresh 1) (if easy-jekyll--draft-list (easy-jekyll-draft-list) (easy-jekyll)) (setq easy-jekyll--refresh nil)) (defun easy-jekyll-sort-time () "Sort article by time on easy-jekyll-mode." (interactive) (if easy-jekyll--draft-list (progn (setq easy-jekyll--sort-char-flg nil) (if (eq 1 easy-jekyll--sort-time-flg) (setq easy-jekyll--sort-time-flg 2) (setq easy-jekyll--sort-time-flg 1)) (easy-jekyll-draft-list)) (progn (setq easy-jekyll--sort-char-flg nil) (if (eq 1 easy-jekyll--sort-time-flg) (setq easy-jekyll--sort-time-flg 2) (setq easy-jekyll--sort-time-flg 1)) (easy-jekyll)))) (defun easy-jekyll-sort-char () "Sort article by characters on easy-jekyll-mode." (interactive) (if easy-jekyll--draft-list (progn (setq easy-jekyll--sort-time-flg nil) (if (eq 1 easy-jekyll--sort-char-flg) (setq easy-jekyll--sort-char-flg 2) (setq easy-jekyll--sort-char-flg 1)) (easy-jekyll-draft-list)) (progn (setq easy-jekyll--sort-time-flg nil) (if (eq 1 easy-jekyll--sort-char-flg) (setq easy-jekyll--sort-char-flg 2) (setq easy-jekyll--sort-char-flg 1)) (easy-jekyll)))) (defun easy-jekyll-forward-char (arg) "Forward-char on easy-jekyll-mode. Optional prefix ARG says how many lines to move. default is one line." (interactive "^p") (when (not (eolp)) (forward-char (or arg 1)))) (defun easy-jekyll-backward-char (arg) "Backward-char on easy-jekyll-mode. Optional prefix ARG says how many lines to move. default is one line." (interactive "^p") (when (not (bolp)) (backward-char (or arg 1)))) (defun easy-jekyll-beginning-of-buffer () "Easy-jekyll beginning-of-buffer." (interactive) (goto-char (point-min)) (forward-line (- easy-jekyll--unmovable-line 1)) (forward-char easy-jekyll--forward-char)) (defun easy-jekyll-backward-word (&optional arg) "Easy-jekyll backward-word. Optional prefix ARG says how many lines to move. default is one line." (interactive "^p") (forward-word (- (or arg 1))) (if (< (line-number-at-pos) easy-jekyll--unmovable-line) (progn (goto-char (point-min)) (forward-line (- easy-jekyll--unmovable-line 1))))) (defun easy-jekyll-next-line (arg) "Move down lines then position at filename. Optional prefix ARG says how many lines to move; default is one line." (interactive "^p") (let ((line-move-visual) (goal-column)) (line-move arg t)) (while (and (invisible-p (point)) (not (if (and arg (< arg 0)) (bobp) (eobp)))) (forward-char (if (and arg (< arg 0)) -1 1))) (beginning-of-line) (forward-char easy-jekyll--forward-char)) (defun easy-jekyll-previous-line (arg) "Move up lines then position at filename. Optional prefix ARG says how many lines to move; default is one line." (interactive "^p") (when (>= (- (line-number-at-pos) arg) easy-jekyll--unmovable-line) (easy-jekyll-next-line (- (or arg 1))))) (defun easy-jekyll-rename (post-file) "Renames file on the pointer to POST-FILE." (interactive (list (read-from-minibuffer "Rename: " `(,easy-jekyll-default-ext . 1) nil nil nil))) (easy-jekyll-with-env (let ((newname (if easy-jekyll--draft-list (expand-file-name post-file "_drafts") (expand-file-name post-file easy-jekyll-postdir))) (file-ext (file-name-extension post-file))) (when (not (member file-ext easy-jekyll--formats)) (error "Please enter .%s file name or .%s file name" easy-jekyll-markdown-extension easy-jekyll-textile-extension)) (when (equal (buffer-name (current-buffer)) easy-jekyll--buffer-name) (when (file-exists-p (file-truename newname)) (error "%s already exists!" newname)) (unless (or (string-match "^ $" (thing-at-point 'line)) (eq (point) (point-max)) (> (+ 1 easy-jekyll--forward-char) (length (thing-at-point 'line)))) (let ((oldname (if easy-jekyll--draft-list (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) "_drafts") (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) easy-jekyll-postdir)))) (rename-file oldname newname 1) (easy-jekyll-refresh))))))) (defun easy-jekyll-undraft () "Undraft file on the pointer." (interactive) (when (equal (buffer-name (current-buffer)) easy-jekyll--buffer-name) (easy-jekyll-with-env (unless (or (string-match "^ $" (thing-at-point 'line)) (eq (point) (point-max)) (> (+ 1 easy-jekyll--forward-char) (length (thing-at-point 'line)))) (let ((file (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) (expand-file-name "_drafts" easy-jekyll-basedir)))) (when (and (file-exists-p file) (not (file-directory-p file))) (unless (file-directory-p (expand-file-name "_drafts" easy-jekyll-basedir)) (make-directory (expand-file-name "_drafts" easy-jekyll-basedir) t)) (rename-file file (expand-file-name (concat (format-time-string "%Y-%m-%d-" (current-time)) (file-name-nondirectory file)) easy-jekyll-postdir) 1) (easy-jekyll-refresh))))))) (defun easy-jekyll-open () "Open the file on the pointer." (interactive) (when (equal (buffer-name (current-buffer)) easy-jekyll--buffer-name) (easy-jekyll-with-env (unless (or (string-match "^ $" (thing-at-point 'line)) (eq (point) (point-max)) (> (+ 1 easy-jekyll--forward-char) (length (thing-at-point 'line)))) (let ((file (expand-file-name (if easy-jekyll--draft-list (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) "_drafts") (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) easy-jekyll-postdir)) easy-jekyll-basedir))) (when (and (file-exists-p file) (not (file-directory-p file))) (find-file file))))))) (defun easy-jekyll-open-other-window () "Open the file on the pointer at other window." (interactive) (when (equal (buffer-name (current-buffer)) easy-jekyll--buffer-name) (easy-jekyll-with-env (unless (or (string-match "^ $" (thing-at-point 'line)) (eq (point) (point-max)) (> (+ 1 easy-jekyll--forward-char) (length (thing-at-point 'line)))) (let ((file (expand-file-name (if easy-jekyll--draft-list (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) "_drafts") (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) easy-jekyll-postdir)) easy-jekyll-basedir))) (when (and (file-exists-p file) (not (file-directory-p file))) (find-file-other-window file))))))) (defun easy-jekyll-open-basedir () "Open `easy-jekyll-basedir' with dired." (interactive) (easy-jekyll-with-env (switch-to-buffer (find-file-noselect easy-jekyll-basedir)))) (defun easy-jekyll-view () "Open the file on the pointer with 'view-mode'." (interactive) (easy-jekyll-with-env (if (equal (buffer-name (current-buffer)) easy-jekyll--buffer-name) (progn (unless (or (string-match "^ $" (thing-at-point 'line)) (eq (point) (point-max)) (> (+ 1 easy-jekyll--forward-char) (length (thing-at-point 'line)))) (let ((file (expand-file-name (if easy-jekyll--draft-list (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) "_drafts") (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) easy-jekyll-postdir)) easy-jekyll-basedir))) (when (and (file-exists-p file) (not (file-directory-p file))) (view-file file))))) (view-file buffer-file-name)))) (defun easy-jekyll-view-other-window () "Open the file on the pointer with 'view-mode' at other window." (interactive) (easy-jekyll-with-env (if (equal (buffer-name (current-buffer)) easy-jekyll--buffer-name) (progn (unless (or (string-match "^ $" (thing-at-point 'line)) (eq (point) (point-max)) (> (+ 1 easy-jekyll--forward-char) (length (thing-at-point 'line)))) (let ((file (expand-file-name (if easy-jekyll--draft-list (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) "_drafts") (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) easy-jekyll-postdir)) easy-jekyll-basedir))) (when (and (file-exists-p file) (not (file-directory-p file))) (view-file-other-window file))))) (view-file-other-window buffer-file-name)))) (defun easy-jekyll-delete () "Delete the file on the pointer." (interactive) (when (equal (buffer-name (current-buffer)) easy-jekyll--buffer-name) (easy-jekyll-with-env (unless (or (string-match "^ $" (thing-at-point 'line)) (eq (point) (point-max)) (> (+ 1 easy-jekyll--forward-char) (length (thing-at-point 'line)))) (let ((file (expand-file-name (if easy-jekyll--draft-list (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) "_drafts") (expand-file-name (substring (thing-at-point 'line) easy-jekyll--forward-char -1) easy-jekyll-postdir)) easy-jekyll-basedir))) (when (and (file-exists-p file) (not (file-directory-p file))) (when (y-or-n-p (concat "Delete " file)) (if easy-jekyll-no-help (setq easy-jekyll--line (- (line-number-at-pos) 4)) (setq easy-jekyll--line (- (line-number-at-pos) (+ easy-jekyll--unmovable-line 1)))) (delete-file file) (if easy-jekyll--draft-list (easy-jekyll-draft-list) (easy-jekyll)) (when (> easy-jekyll--line 0) (forward-line easy-jekyll--line) (forward-char easy-jekyll--forward-char))))))))) (defun easy-jekyll-next-blog () "Go to next blog." (interactive) (when (< 1 (length easy-jekyll-bloglist)) (if (eq (- (length easy-jekyll-bloglist) 1) easy-jekyll--current-blog) (setq easy-jekyll--current-blog 0) (setq easy-jekyll--current-blog (+ easy-jekyll--current-blog 1))) (setq easy-jekyll--postdir-list nil) (setq easy-jekyll--current-postdir 0) (easy-jekyll-set-bloglist easy-jekyll-basedir) (easy-jekyll-set-bloglist easy-jekyll-url) (easy-jekyll-set-bloglist easy-jekyll-root) (easy-jekyll-set-bloglist easy-jekyll-sshdomain) (easy-jekyll-set-bloglist easy-jekyll-amazon-s3-bucket-name) (easy-jekyll-set-bloglist easy-jekyll-google-cloud-storage-bucket-name) (if (easy-jekyll-eval-bloglist easy-jekyll-github-deploy-script) (easy-jekyll-set-bloglist easy-jekyll-github-deploy-script) (setq easy-jekyll-github-deploy-script easy-jekyll--default-github-deploy-script)) (if (easy-jekyll-eval-bloglist easy-jekyll-image-directory) (easy-jekyll-set-bloglist easy-jekyll-image-directory) (setq easy-jekyll-image-directory easy-jekyll--default-image-directory)) (if (easy-jekyll-eval-bloglist easy-jekyll-default-picture-directory) (easy-jekyll-set-bloglist easy-jekyll-default-picture-directory) (setq easy-jekyll-default-picture-directory easy-jekyll--default-picture-directory)) (if (easy-jekyll-eval-bloglist easy-jekyll-publish-chmod) (easy-jekyll-set-bloglist easy-jekyll-publish-chmod) (setq easy-jekyll-publish-chmod easy-jekyll--default-publish-chmod)) (if (easy-jekyll-eval-bloglist easy-jekyll-previewtime) (easy-jekyll-set-bloglist easy-jekyll-previewtime) (setq easy-jekyll-previewtime easy-jekyll--default-previewtime)) (if (easy-jekyll-eval-bloglist easy-jekyll-preview-url) (easy-jekyll-set-bloglist easy-jekyll-preview-url) (setq easy-jekyll-preview-url easy-jekyll--default-preview-url)) (if (easy-jekyll-eval-bloglist easy-jekyll-sort-default-char) (easy-jekyll-set-bloglist easy-jekyll-sort-default-char) (setq easy-jekyll-sort-default-char easy-jekyll--default-sort-default-char)) (if (easy-jekyll-eval-bloglist easy-jekyll-textile-extension) (easy-jekyll-set-bloglist easy-jekyll-textile-extension) (setq easy-jekyll-textile-extension easy-jekyll--default-textile-extension)) (if (easy-jekyll-eval-bloglist easy-jekyll-markdown-extension) (easy-jekyll-set-bloglist easy-jekyll-markdown-extension) (setq easy-jekyll-markdown-extension easy-jekyll--default-markdown-extension)) (if (easy-jekyll-eval-bloglist easy-jekyll-default-ext) (easy-jekyll-set-bloglist easy-jekyll-default-ext) (setq easy-jekyll-default-ext easy-jekyll--default-ext)) (if (easy-jekyll-eval-bloglist easy-jekyll-postdir) (easy-jekyll-set-bloglist easy-jekyll-postdir) (setq easy-jekyll-postdir easy-jekyll--default-postdir)) (easy-jekyll--preview-end) (easy-jekyll))) (defun easy-jekyll-previous-blog () "Go to previous blog." (interactive) (when (< 1 (length easy-jekyll-bloglist)) (if (= 0 easy-jekyll--current-blog) (setq easy-jekyll--current-blog (- (length easy-jekyll-bloglist) 1)) (setq easy-jekyll--current-blog (- easy-jekyll--current-blog 1))) (setq easy-jekyll--postdir-list nil) (setq easy-jekyll--current-postdir 0) (easy-jekyll-set-bloglist easy-jekyll-basedir) (easy-jekyll-set-bloglist easy-jekyll-url) (easy-jekyll-set-bloglist easy-jekyll-root) (easy-jekyll-set-bloglist easy-jekyll-sshdomain) (easy-jekyll-set-bloglist easy-jekyll-amazon-s3-bucket-name) (easy-jekyll-set-bloglist easy-jekyll-google-cloud-storage-bucket-name) (if (easy-jekyll-eval-bloglist easy-jekyll-github-deploy-script) (easy-jekyll-set-bloglist easy-jekyll-github-deploy-script) (setq easy-jekyll-github-deploy-script easy-jekyll--default-github-deploy-script)) (if (easy-jekyll-eval-bloglist easy-jekyll-image-directory) (easy-jekyll-set-bloglist easy-jekyll-image-directory) (setq easy-jekyll-image-directory easy-jekyll--default-image-directory)) (if (easy-jekyll-eval-bloglist easy-jekyll-default-picture-directory) (easy-jekyll-set-bloglist easy-jekyll-default-picture-directory) (setq easy-jekyll-default-picture-directory easy-jekyll--default-picture-directory)) (if (easy-jekyll-eval-bloglist easy-jekyll-publish-chmod) (easy-jekyll-set-bloglist easy-jekyll-publish-chmod) (setq easy-jekyll-publish-chmod easy-jekyll--default-publish-chmod)) (if (easy-jekyll-eval-bloglist easy-jekyll-previewtime) (easy-jekyll-set-bloglist easy-jekyll-previewtime) (setq easy-jekyll-previewtime easy-jekyll--default-previewtime)) (if (easy-jekyll-eval-bloglist easy-jekyll-preview-url) (easy-jekyll-set-bloglist easy-jekyll-preview-url) (setq easy-jekyll-preview-url easy-jekyll--default-preview-url)) (if (easy-jekyll-eval-bloglist easy-jekyll-sort-default-char) (easy-jekyll-set-bloglist easy-jekyll-sort-default-char) (setq easy-jekyll-sort-default-char easy-jekyll--default-sort-default-char)) (if (easy-jekyll-eval-bloglist easy-jekyll-textile-extension) (easy-jekyll-set-bloglist easy-jekyll-textile-extension) (setq easy-jekyll-textile-extension easy-jekyll--default-textile-extension)) (if (easy-jekyll-eval-bloglist easy-jekyll-markdown-extension) (easy-jekyll-set-bloglist easy-jekyll-markdown-extension) (setq easy-jekyll-markdown-extension easy-jekyll--default-markdown-extension)) (if (easy-jekyll-eval-bloglist easy-jekyll-default-ext) (easy-jekyll-set-bloglist easy-jekyll-default-ext) (setq easy-jekyll-default-ext easy-jekyll--default-ext)) (if (easy-jekyll-eval-bloglist easy-jekyll-postdir) (easy-jekyll-set-bloglist easy-jekyll-postdir) (setq easy-jekyll-postdir easy-jekyll--default-postdir)) (easy-jekyll--preview-end) (easy-jekyll))) (defun easy-jekyll-nth-blog (n) "Go to blog of number N." (interactive "nBlog number:") (when (or (< n 0) (>= n (length easy-jekyll-bloglist))) (error "Blog %s does not exist" n)) (when (and (< 1 (length easy-jekyll-bloglist)) (< n (length easy-jekyll-bloglist))) (setq easy-jekyll--current-blog n) (setq easy-jekyll--postdir-list nil) (setq easy-jekyll--current-postdir 0) (easy-jekyll-set-bloglist easy-jekyll-basedir) (easy-jekyll-set-bloglist easy-jekyll-url) (easy-jekyll-set-bloglist easy-jekyll-root) (easy-jekyll-set-bloglist easy-jekyll-sshdomain) (easy-jekyll-set-bloglist easy-jekyll-amazon-s3-bucket-name) (easy-jekyll-set-bloglist easy-jekyll-google-cloud-storage-bucket-name) (if (easy-jekyll-eval-bloglist easy-jekyll-github-deploy-script) (easy-jekyll-set-bloglist easy-jekyll-github-deploy-script) (setq easy-jekyll-github-deploy-script easy-jekyll--default-github-deploy-script)) (if (easy-jekyll-eval-bloglist easy-jekyll-image-directory) (easy-jekyll-set-bloglist easy-jekyll-image-directory) (setq easy-jekyll-image-directory easy-jekyll--default-image-directory)) (if (easy-jekyll-eval-bloglist easy-jekyll-default-picture-directory) (easy-jekyll-set-bloglist easy-jekyll-default-picture-directory) (setq easy-jekyll-default-picture-directory easy-jekyll--default-picture-directory)) (if (easy-jekyll-eval-bloglist easy-jekyll-publish-chmod) (easy-jekyll-set-bloglist easy-jekyll-publish-chmod) (setq easy-jekyll-publish-chmod easy-jekyll--default-publish-chmod)) (if (easy-jekyll-eval-bloglist easy-jekyll-previewtime) (easy-jekyll-set-bloglist easy-jekyll-previewtime) (setq easy-jekyll-previewtime easy-jekyll--default-previewtime)) (if (easy-jekyll-eval-bloglist easy-jekyll-preview-url) (easy-jekyll-set-bloglist easy-jekyll-preview-url) (setq easy-jekyll-preview-url easy-jekyll--default-preview-url)) (if (easy-jekyll-eval-bloglist easy-jekyll-sort-default-char) (easy-jekyll-set-bloglist easy-jekyll-sort-default-char) (setq easy-jekyll-sort-default-char easy-jekyll--default-sort-default-char)) (if (easy-jekyll-eval-bloglist easy-jekyll-textile-extension) (easy-jekyll-set-bloglist easy-jekyll-textile-extension) (setq easy-jekyll-textile-extension easy-jekyll--default-textile-extension)) (if (easy-jekyll-eval-bloglist easy-jekyll-markdown-extension) (easy-jekyll-set-bloglist easy-jekyll-markdown-extension) (setq easy-jekyll-markdown-extension easy-jekyll--default-markdown-extension)) (if (easy-jekyll-eval-bloglist easy-jekyll-default-ext) (easy-jekyll-set-bloglist easy-jekyll-default-ext) (setq easy-jekyll-default-ext easy-jekyll--default-ext)) (if (easy-jekyll-eval-bloglist easy-jekyll-postdir) (easy-jekyll-set-bloglist easy-jekyll-postdir) (setq easy-jekyll-postdir easy-jekyll--default-postdir)) (easy-jekyll--preview-end) (easy-jekyll))) (defun easy-jekyll-next-postdir () "Go to next postdir." (interactive) (add-to-list 'easy-jekyll--postdir-list (expand-file-name easy-jekyll-basedir)) (add-to-list 'easy-jekyll--postdir-list (expand-file-name "_posts" easy-jekyll-basedir)) (if (eq (- (length easy-jekyll--postdir-list) 1) easy-jekyll--current-postdir) (setq easy-jekyll--current-postdir 0) (setq easy-jekyll--current-postdir (+ easy-jekyll--current-postdir 1))) (setq easy-jekyll-postdir (file-relative-name (nth easy-jekyll--current-postdir easy-jekyll--postdir-list) easy-jekyll-basedir)) (easy-jekyll)) (defun easy-jekyll-previous-postdir () "Go to previous postdir." (interactive) (add-to-list 'easy-jekyll--postdir-list (expand-file-name easy-jekyll-basedir)) (add-to-list 'easy-jekyll--postdir-list (expand-file-name "_posts" easy-jekyll-basedir)) (setq easy-jekyll--current-postdir (- easy-jekyll--current-postdir 1)) (when (> 0 easy-jekyll--current-postdir) (setq easy-jekyll--current-postdir (- (length easy-jekyll--postdir-list) 1))) (setq easy-jekyll-postdir (file-relative-name (nth easy-jekyll--current-postdir easy-jekyll--postdir-list) easy-jekyll-basedir)) (easy-jekyll)) (defun easy-jekyll-draft-list () "Drafts list mode of easy-jekyll." (easy-jekyll-with-env (unless (file-directory-p (expand-file-name "_drafts" easy-jekyll-basedir)) (make-directory (expand-file-name "_drafts" easy-jekyll-basedir) t)) (setq easy-jekyll--mode-buffer (get-buffer-create easy-jekyll--buffer-name)) (setq easy-jekyll--draft-list 1) (switch-to-buffer easy-jekyll--mode-buffer) (setq-local default-directory easy-jekyll-basedir) (setq buffer-read-only nil) (erase-buffer) (insert (propertize (concat "Easy-jekyll " easy-jekyll-url easy-jekyll--draft-mode "\n\n") 'face 'easy-jekyll-help-face)) (unless easy-jekyll-no-help (insert (propertize easy-jekyll-help 'face 'easy-jekyll-help-face)) (when easy-jekyll-additional-help (insert (propertize easy-jekyll-add-help 'face 'easy-jekyll-help-face))) (insert (propertize (concat "\n")'face 'easy-jekyll-help-face))) (unless easy-jekyll--refresh (setq easy-jekyll--cursor (point))) (let ((files (directory-files (expand-file-name "_drafts" easy-jekyll-basedir))) (lists (list))) (if (eq 2 (length files)) (progn (easy-jekyll-mode) (goto-char easy-jekyll--cursor)) (progn (cond ((eq 1 easy-jekyll--sort-char-flg) (setq files (reverse (sort files 'string<)))) ((eq 2 easy-jekyll--sort-char-flg) (setq files (sort files 'string<)))) (while files (unless (or (string= (car files) ".") (string= (car files) "..") (not (member (file-name-extension (car files)) easy-jekyll--formats))) (push (concat (format-time-string "%Y-%m-%d %H:%M:%S " (nth 5 (file-attributes (expand-file-name (car files) easy-jekyll-postdir)))) (car files)) lists)) (pop files)) (cond ((eq 1 easy-jekyll--sort-time-flg) (setq lists (reverse (sort lists 'string<)))) ((eq 2 easy-jekyll--sort-time-flg) (setq lists (sort lists 'string<)))) (while lists (insert (concat (car lists) "\n")) (pop lists)) (goto-char easy-jekyll--cursor) (if easy-jekyll--refresh (progn (when (< (line-number-at-pos) easy-jekyll--unmovable-line) (goto-char (point-min)) (forward-line (- easy-jekyll--unmovable-line 1))) (beginning-of-line) (forward-char easy-jekyll--forward-char)) (forward-char easy-jekyll--forward-char)) (easy-jekyll-mode)))))) ;;;###autoload (defun easy-jekyll () "Easy jekyll mode." (interactive) (easy-jekyll-with-env (unless (file-directory-p (expand-file-name easy-jekyll-postdir easy-jekyll-basedir)) (error "%s%s doesn't exist!" easy-jekyll-basedir easy-jekyll-postdir)) (setq easy-jekyll--mode-buffer (get-buffer-create easy-jekyll--buffer-name)) (setq easy-jekyll--draft-list nil) (switch-to-buffer easy-jekyll--mode-buffer) (setq-local default-directory easy-jekyll-basedir) (setq buffer-read-only nil) (erase-buffer) (if (equal easy-jekyll-postdir "./") (insert (propertize (concat "Easy-jekyll " easy-jekyll-url "\n\n") 'face 'easy-jekyll-help-face)) (insert (propertize (concat "Easy-jekyll " easy-jekyll-url "/" easy-jekyll-postdir "\n\n") 'face 'easy-jekyll-help-face))) (unless easy-jekyll-no-help (insert (propertize easy-jekyll-help 'face 'easy-jekyll-help-face)) (when easy-jekyll-additional-help (insert (propertize easy-jekyll-add-help 'face 'easy-jekyll-help-face))) (insert (propertize (concat "\n")'face 'easy-jekyll-help-face))) (unless easy-jekyll--refresh (setq easy-jekyll--cursor (point))) (let ((files (directory-files (expand-file-name easy-jekyll-postdir easy-jekyll-basedir))) (lists (list))) (if (eq 2 (length files)) (progn (insert easy-jekyll--first-help) (easy-jekyll-mode) (goto-char easy-jekyll--cursor)) (progn (cond ((eq 1 easy-jekyll--sort-char-flg) (setq files (reverse (sort files 'string<)))) ((eq 2 easy-jekyll--sort-char-flg) (setq files (sort files 'string<)))) (while files (unless (or (string= (car files) ".") (string= (car files) "..") (not (member (file-name-extension (car files)) easy-jekyll--formats))) (push (concat (format-time-string "%Y-%m-%d %H:%M:%S " (nth 5 (file-attributes (expand-file-name (car files) easy-jekyll-postdir)))) (car files)) lists)) (pop files)) (cond ((eq 1 easy-jekyll--sort-time-flg) (setq lists (reverse (sort lists 'string<)))) ((eq 2 easy-jekyll--sort-time-flg) (setq lists (sort lists 'string<)))) (while lists (insert (concat (car lists) "\n")) (pop lists)) (goto-char easy-jekyll--cursor) (if easy-jekyll--refresh (progn (when (< (line-number-at-pos) easy-jekyll--unmovable-line) (goto-char (point-min)) (forward-line (- easy-jekyll--unmovable-line 1))) (beginning-of-line) (forward-char easy-jekyll--forward-char)) (forward-char easy-jekyll--forward-char)) (easy-jekyll-mode)))))) (provide 'easy-jekyll) ;;; easy-jekyll.el ends here