;;; ein-cell-edit.el --- Notebook cell editing ;; Copyright (C) 2016 John M. Miller ;; Author: John Miller ;; This file is NOT part of GNU Emacs. ;; ein-cell-edit.el 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. ;; ein-cell-edit.el 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 ein-worksheet.el. If not, see . ;;; Commentary: ;; This code inspired by borrowing from org-src.el. ;;; Code: (require 'ein-cell) (defvar ein:src--cell nil) (defvar ein:src--ws nil) (defvar ein:src--allow-write-back t) (defvar ein:edit-cell-mode-map (let ((map (make-sparse-keymap))) (define-key map "\C-c'" 'ein:edit-cell-exit) (define-key map "\C-c\C-k" 'ein:edit-cell-abort) (define-key map "\C-c\C-c" 'ein:edit-cell-execute) (define-key map "\C-x\C-s" 'ein:edit-cell-save) map)) (define-minor-mode ein:edit-cell-mode "Minor mode for language major mode buffers generated by EIN. \\ This minor mode is turned on when editing a source code snippet with \\[org-edit-special] \\{ein:edit-cell-mode-map} See also `org-src-mode-hook'." nil " EinCell" nil (set (make-local-variable 'header-line-format) (substitute-command-keys "Edit, then exit with \\[ein:edit-cell-exit] or abort with \ \\[ein:edit-cell-abort]")) ;; Possibly activate various auto-save features (for the edit buffer ;; or the source buffer). ;; (when org-edit-src-turn-on-auto-save ;; (setq buffer-auto-save-file-name ;; (concat (make-temp-name "org-src-") ;; (format-time-string "-%Y-%d-%m") ;; ".txt"))) ;; (unless (or org-src--auto-save-timer (zerop org-edit-src-auto-save-idle-delay)) ;; (setq org-src--auto-save-timer ;; (run-with-idle-timer ;; org-edit-src-auto-save-idle-delay t ;; (lambda () ;; (save-excursion ;; (let (edit-flag) ;; (dolist (b (buffer-list)) ;; (with-current-buffer b ;; (when (org-src-edit-buffer-p) ;; (unless edit-flag (setq edit-flag t)) ;; (when (buffer-modified-p) (org-edit-src-save))))) ;; (unless edit-flag ;; (cancel-timer org-src--auto-save-timer) ;; (setq org-src--auto-save-timer nil)))))))) ) (defun ein:cell-configure-edit-buffer () (when (org-bound-and-true-p org-src--from-org-mode) (org-add-hook 'kill-buffer-hook #'org-src--remove-overlay nil 'local) (if (org-bound-and-true-p org-src--allow-write-back) (progn (setq buffer-offer-save t) (setq buffer-file-name (concat (buffer-file-name (marker-buffer org-src--beg-marker)) "[" (buffer-name) "]")) (setq write-contents-functions '(ein:edit-cell-save))) (setq buffer-read-only t)))) (defun ein:edit-cell-execute () "Execute buffer contents via `ein:shared-output-eval-string'." (interactive) (ein:edit-cell-save) (ein:cell-execute-internal ein:src--cell (slot-value ein:src--cell 'kernel) (buffer-string) :silent nil)) (defun ein:edit-cell-save () (interactive) ;;(unless (ein:cell-edit-buffer-p) (user-error "Not in a sub-editing buffer")) (set-buffer-modified-p nil) (let ((edited-code (buffer-string) ;;(org-src--contents-for-write-back) ) ;; (beg org-src--beg-marker) ;; (end org-src--end-marker) ;; (overlay org-src--overlay) ) (setf (slot-value ein:src--cell 'input) edited-code) (ein:worksheet-render ein:src--ws))) (defun ein:edit-cell-exit () (interactive) ;;(unless (org-src-edit-buffer-p) (error "Not in a sub-editing buffer")) (let ((edit-buffer (current-buffer)) (ws ein:src--ws)) (when ein:src--allow-write-back (ein:edit-cell-save)) (kill-buffer edit-buffer) (switch-to-buffer-other-window (ein:worksheet-buffer ws)) ;; FIXME: put point at an appropriate location as org does? )) (defun ein:edit-cell-abort () (interactive) (let (ein:src--allow-write-back) (ein:edit-cell-exit))) (defun ein:construct-cell-edit-buffer-name (bufname cell-type) (concat "*EIN Src " bufname "[ " cell-type " ]*" )) (defun ein:edit-cell-contents () (interactive) (let* ((cell (or (ein:worksheet-get-current-cell) (error "Must be called from inside an EIN worksheet cell."))) (ws (ein:worksheet--get-ws-or-error)) (contents (ein:cell-get-text cell)) (type (slot-value cell 'cell-type)) (name (ein:construct-cell-edit-buffer-name (buffer-name) type)) (buffer (generate-new-buffer-name name))) (switch-to-buffer-other-window buffer) (insert contents) (remove-text-properties (point-min) (point-max) '(display nil invisible nil intangible nil)) (set-buffer-modified-p nil) (setq buffer-file-name nil) (condition-case e (ein:case-equal type (("markdown") (markdown-mode)) (("code") (python-mode))) (error (message "Language mode `%s' fails with: %S" type (nth 1 e)))) (set (make-local-variable 'ein:src--cell) cell) (set (make-local-variable 'ein:src--ws) ws) (set (make-local-variable 'ein:src--allow-write-back) t) (ein:edit-cell-mode))) (provide 'ein-cell-edit)