2012-05-07 14:41:15 +02:00
;;; ein-notebooklist.el --- Notebook list buffer
2018-04-22 10:22:11 -05:00
;; Copyright (C) 2018- John M. Miller
2012-05-07 14:41:15 +02:00
2015-01-31 10:13:49 -06:00
;; Authors: Takafumi Arakaki <aka.tkf at gmail.com>
;; John M. Miller <millejoh at mac.com>
2012-05-07 14:41:15 +02:00
;; This file is NOT part of GNU Emacs.
;; ein-notebooklist.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-notebooklist.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-notebooklist.el. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
2018-03-31 14:38:25 -07:00
;; The rendering is split into a function for ipython2 and one for
;; ipython3, ein:notebooklist-render-ipy2 and
2018-03-25 13:42:35 -07:00
;; ein:notebooklist-render.
2012-05-07 14:41:15 +02:00
;;; Code:
( eval-when-compile ( require 'cl ) )
( require 'widget )
2018-05-31 13:15:04 -05:00
( require 'cus-edit )
2012-05-07 14:41:15 +02:00
2012-08-28 15:26:32 +02:00
( require 'ein-core )
2012-05-07 14:41:15 +02:00
( require 'ein-notebook )
2018-03-10 07:07:37 -06:00
( require 'ein-connect )
2017-04-20 07:47:05 -05:00
( require 'ein-file )
2015-02-10 14:53:08 -06:00
( require 'ein-contents-api )
2012-05-19 15:47:09 +02:00
( require 'ein-subpackages )
2017-05-30 14:33:31 -05:00
( require 'deferred )
2017-09-30 14:35:36 +09:00
( require 'dash )
2012-05-07 14:41:15 +02:00
2018-03-25 13:30:50 -07:00
( defcustom ein:notebook-list-render-order
' ( render-header
render-opened-notebooks
2018-03-31 14:38:25 -07:00
render-directory-ipy3 )
2018-03-25 13:30:50 -07:00
" Order of notebook list sections.
2018-03-31 14:38:25 -07:00
Must contain render-header, render-opened-notebooks, and render-directory-ipy3. "
2018-03-25 13:30:50 -07:00
:group 'ein
:type 'list
)
2012-07-05 00:13:12 +02:00
( defcustom ein:notebooklist-first-open-hook nil
" Hooks to run when the notebook list is opened at first time.
Example to open a notebook named _scratch_ when the notebook list
is opened at first time.::
( add-hook
'ein:notebooklist-first-open-hook
( lambda ( ) ( ein:notebooklist-open-notebook-by-name \"_scratch_\" ) ) )
"
:type 'hook
:group 'ein )
2012-05-13 02:51:47 +02:00
( defstruct ein:$notebooklist
" Hold notebooklist variables.
` ein:$notebooklist-url-or-port '
URL or port of IPython server.
2014-09-12 12:37:24 -05:00
` ein:$notbooklist-path '
2014-09-11 20:04:00 -05:00
The path for the notebooklist.
2012-05-13 02:51:47 +02:00
` ein:$notebooklist-data '
2014-10-17 16:44:04 -05:00
JSON data sent from the server.
` ein:$notebooklist-api-version '
Major version of the IPython notebook server we are talking to. "
2012-05-13 02:51:47 +02:00
url-or-port
2014-09-11 20:04:00 -05:00
path
2014-10-17 16:44:04 -05:00
data
api-version )
2012-05-13 02:51:47 +02:00
2012-08-18 22:31:15 +02:00
( ein:deflocal ein:%notebooklist% nil
2012-05-13 02:51:47 +02:00
" Buffer local variable to store an instance of `ein:$notebooklist' . " )
2018-04-22 20:57:01 -05:00
2018-05-31 13:15:04 -05:00
( defcustom ein:notebooklist-sort-field :name
" The notebook list sort field. "
:type ' ( choice ( const :tag " Name " :name )
( const :tag " Last modified " :last_modified ) )
:group 'ein )
( make-variable-buffer-local 'ein:notebooklist-sort-field )
( put 'ein:notebooklist-sort-field 'permanent-local t )
( defcustom ein:notebooklist-sort-order :ascending
" The notebook list sort order. "
:type ' ( choice ( const :tag " Ascending " :ascending )
( const :tag " Descending " :descending ) )
:group 'ein )
( make-variable-buffer-local 'ein:notebooklist-sort-order )
( put 'ein:notebooklist-sort-order 'permanent-local t )
2018-05-04 15:07:32 -04:00
( defmacro ein:make-sorting-widget ( tag custom-var )
" Create the sorting widget. "
;; assume that custom-var has type `choice' of `const's.
` ( widget-create
'menu-choice :tag , tag
:value , custom-var
:notify ( lambda ( widget &rest ignore )
( run-at-time 1 nil
#' ein:notebooklist-reload
ein:%notebooklist% )
( setq , custom-var ( widget-value widget ) ) )
,@ ( mapcar ( lambda ( const )
` ' ( item :tag , ( third const ) :value , ( fourth const ) ) )
( rest ( custom-variable-type custom-var ) ) ) ) )
2018-04-22 20:57:01 -05:00
2012-08-18 22:31:15 +02:00
( define-obsolete-variable-alias 'ein:notebooklist 'ein:%notebooklist% " 0.1.2 " )
2012-05-07 14:41:15 +02:00
( defvar ein:notebooklist-buffer-name-template " *ein:notebooklist %s* " )
2012-06-26 17:45:51 +02:00
( defvar ein:notebooklist-map ( make-hash-table :test 'equal )
" Data store for `ein:notebooklist-list' .
Mapping from URL-OR-PORT to an instance of ` ein:$notebooklist '. " )
2012-06-05 14:54:18 +02:00
2012-06-26 17:45:51 +02:00
( defun ein:notebooklist-list ( )
" Get a list of opened `ein:$notebooklist' . "
( ein:hash-vals ein:notebooklist-map ) )
( defun ein:notebooklist-list-add ( nblist )
" Register notebook list instance NBLIST for global lookup.
This function adds NBLIST to ` ein:notebooklist-map '. "
( puthash ( ein:$notebooklist-url-or-port nblist )
nblist
ein:notebooklist-map ) )
2012-05-07 14:41:15 +02:00
2012-07-05 00:13:12 +02:00
( defun ein:notebooklist-list-get ( url-or-port )
" Get an instance of `ein:$notebooklist' by URL-OR-PORT as a key. "
( gethash url-or-port ein:notebooklist-map ) )
2015-02-10 14:53:08 -06:00
;; TODO: FIXME. Use content API.
2012-07-12 02:56:23 +02:00
( defun ein:notebooklist-open-notebook-by-name ( name &optional url-or-port
callback cbargs )
2012-07-05 00:13:12 +02:00
" Open notebook named NAME in the server URL-OR-PORT.
If URL-OR-PORT is not given or ` nil ', and the current buffer is
the notebook list buffer, the notebook is searched in the
2012-07-12 02:56:23 +02:00
notebook list of the current buffer.
When used in lisp, CALLBACK and CBARGS are passed to ` ein:notebook-open '.
2018-05-27 12:04:13 -04:00
To suppress popup, you can pass ` ignore ' as CALLBACK. "
2012-07-05 00:13:12 +02:00
( loop with nblist = ( if url-or-port
( ein:notebooklist-list-get url-or-port )
2012-08-18 22:31:15 +02:00
ein:%notebooklist% )
2012-07-05 00:13:12 +02:00
for note in ( ein:$notebooklist-data nblist )
for notebook-name = ( plist-get note :name )
2014-09-11 20:04:00 -05:00
for notebook-path = ( plist-get note :path )
2012-07-05 00:13:12 +02:00
when ( equal notebook-name name )
return ( ein:notebook-open ( ein:$notebooklist-url-or-port nblist )
2016-01-13 07:52:02 -06:00
notebook-path nil callback cbargs ) ) )
2012-07-05 00:13:12 +02:00
2014-10-17 16:44:04 -05:00
( defun ein:notebooklist-url ( url-or-port version &optional path )
( let ( ( base-path ( cond ( ( = version 2 ) " api/notebooks " )
2016-11-11 09:48:47 -08:00
( ( >= version 3 ) " api/contents " ) ) ) )
2014-10-17 16:44:04 -05:00
( if path
( ein:url url-or-port base-path ( or path " " ) )
( ein:url url-or-port base-path ) ) ) )
( defun ein:notebooklist-new-url ( url-or-port version &optional path )
( let ( ( base-path ( cond ( ( = version 2 ) " api/notebooks " )
2016-11-11 09:48:47 -08:00
( ( >= version 3 ) " api/contents " ) ) ) )
2014-10-17 16:44:04 -05:00
( ein:log 'info " New notebook. Port: %s, Path: %s " url-or-port path )
( if ( and path ( not ( string= path " " ) ) )
( ein:url url-or-port base-path path )
( ein:url url-or-port base-path ) ) ) )
2012-05-12 00:34:00 +02:00
2012-05-13 02:51:47 +02:00
( defun ein:notebooklist-get-buffer ( url-or-port )
2012-05-12 00:34:00 +02:00
( get-buffer-create
2012-05-13 02:51:47 +02:00
( format ein:notebooklist-buffer-name-template url-or-port ) ) )
2012-05-12 00:34:00 +02:00
2012-06-09 01:02:53 +02:00
( defun ein:notebooklist-ask-url-or-port ( )
( let* ( ( url-or-port-list ( mapcar ( lambda ( x ) ( format " %s " x ) )
ein:url-or-port ) )
2012-08-13 19:19:23 +02:00
( default ( format " %s " ( ein:aif ( ein:get-notebook )
2012-06-15 21:55:32 +02:00
( ein:$notebook-url-or-port it )
2012-08-18 22:31:15 +02:00
( ein:aif ein:%notebooklist%
2012-06-15 21:55:32 +02:00
( ein:$notebooklist-url-or-port it )
( ein:default-url-or-port ) ) ) ) )
2012-06-09 01:02:53 +02:00
( url-or-port
2012-06-17 09:08:33 +02:00
( completing-read ( format " URL or port number (default %s): " default )
2012-06-09 01:02:53 +02:00
url-or-port-list
nil nil nil nil
2012-06-12 18:58:38 +02:00
default ) ) )
2012-06-09 01:02:53 +02:00
( if ( string-match " ^[0-9]+$ " url-or-port )
( string-to-number url-or-port )
2018-08-29 17:32:09 -05:00
( unless ( string-match " ^https?: " url-or-port )
( error " EIN doesn't want to assume what protocol you are using (http or https), so could you please specify the full URL (e.g http://my.jupyter.url:8888? " ) )
2012-06-09 01:02:53 +02:00
url-or-port ) ) )
2012-05-14 18:47:08 +02:00
;;;###autoload
2014-09-11 20:04:00 -05:00
( defun ein:notebooklist-open ( &optional url-or-port path no-popup )
2012-05-12 00:59:15 +02:00
" Open notebook list buffer. "
2012-06-09 01:02:53 +02:00
( interactive ( list ( ein:notebooklist-ask-url-or-port ) ) )
2012-06-15 21:46:55 +02:00
( unless url-or-port ( setq url-or-port ( ein:default-url-or-port ) ) )
2014-09-12 12:37:24 -05:00
( unless path ( setq path " " ) )
2017-10-03 10:04:41 -05:00
( if ( and ( stringp url-or-port ) ( not ( string-match-p " ^https? " url-or-port ) ) )
2015-07-08 16:17:54 -05:00
( setq url-or-port ( format " http://%s " url-or-port ) ) )
2017-10-21 22:07:02 +09:00
( ein:log 'debug " NOTEBOOKLIST-OPEN: %s/%s " url-or-port path )
2016-02-02 12:12:46 -06:00
( ein:subpackages-load )
2015-02-10 14:53:08 -06:00
( let ( ( success
2012-05-26 16:57:42 +02:00
( if no-popup
#' ein:notebooklist-url-retrieve-callback
2015-02-10 14:53:08 -06:00
( lambda ( content )
2012-05-26 16:57:42 +02:00
( pop-to-buffer
2015-02-10 14:53:08 -06:00
( funcall #' ein:notebooklist-url-retrieve-callback content ) ) ) ) ) )
2018-01-10 09:36:27 -06:00
( ein:query-kernelspecs url-or-port )
2017-06-30 21:41:16 -05:00
( ein:content-query-contents path url-or-port t success ) )
2017-01-11 07:42:06 -06:00
;(ein:notebooklist-get-buffer url-or-port)
)
2012-05-07 14:41:15 +02:00
2018-05-20 08:42:42 -05:00
;;;###autoload
( defun ein:notebooklist-refresh-kernelspecs ( &optional url-or-port )
( interactive ( list ( or ( and ein:%notebooklist% ( ein:$notebooklist-url-or-port ein:%notebooklist% ) )
( ein:notebooklist-ask-url-or-port ) ) ) )
( unless url-or-port
( if ein:%notebooklist%
( setq url-or-port ( ein:$notebooklist-url-or-port ein:%notebooklist% ) )
( setq url-or-port ( ein:default-url-or-port ) ) ) )
( ein:query-kernelspecs url-or-port t )
( when ein:%notebooklist%
( ein:notebooklist-reload ein:%notebooklist% ) ) )
2017-01-31 10:44:04 -06:00
( defcustom ein:notebooklist-keepalive-refresh-time 1
" When the notebook keepalive is enabled, the frequency, IN
HOURS, with which to make calls to the jupyter content API to
refresh the notebook connection. "
:type 'float
:group 'ein )
2017-02-15 19:33:35 -06:00
( defcustom ein:enable-keepalive nil
" When non-nil, will cause EIN to automatically call
` ein:notebooklist-enable-keepalive ' after any call to
` ein:notebooklist-open '. "
:type 'boolean
:group 'ein )
2018-04-23 17:33:13 -04:00
( defcustom ein:notebooklist-date-format " %x "
" The format spec for date in notebooklist mode.
2018-05-25 11:43:39 -04:00
See ` ein:format-time-string '. "
2018-04-23 17:33:13 -04:00
:type ' ( or string function )
:group 'ein )
2017-01-31 10:44:04 -06:00
( defvar ein:notebooklist--keepalive-timer nil )
;;;###autoload
( defun ein:notebooklist-enable-keepalive ( &optional url-or-port )
2017-02-01 09:25:47 -06:00
" Enable periodic calls to the notebook server to keep long running sessions from expiring.
By long running we mean sessions to last days, or weeks. The
frequency of the refresh ( which is very similar to a call to
` ein:notebooklist-open ` ) is controlled by
` ein:notebooklist-keepalive-refresh-time ` , and is measured in
2017-02-16 09:01:14 -06:00
terms of hours. If ` ein:enable-keepalive ' is non-nil this will
automatically be called during calls to ` ein:notebooklist-open ` . "
2017-01-31 10:44:04 -06:00
( interactive ( list ( ein:notebooklist-ask-url-or-port ) ) )
2017-02-15 19:33:35 -06:00
( unless ein:notebooklist--keepalive-timer
( message " Enabling notebooklist keepalive... " )
( let ( ( success
( lambda ( content )
( ein:log 'info " Refreshing notebooklist connection. " ) ) )
( refresh-time ( * ein:notebooklist-keepalive-refresh-time 60 60 ) ) )
( setq ein:notebooklist--keepalive-timer
( run-at-time 0.1 refresh-time #' ein:content-query-contents " " url-or-port nil success ) ) ) ) )
2017-01-31 10:44:04 -06:00
;;;###autoload
( defun ein:notebooklist-disable-keepalive ( )
2017-02-01 09:25:47 -06:00
" Disable the notebooklist keepalive calls to the jupyter notebook server. "
2017-01-31 10:44:04 -06:00
( interactive )
2017-02-15 19:33:35 -06:00
( message " Disabling notebooklist keepalive... " )
2017-02-16 09:01:14 -06:00
( cancel-timer ein:notebooklist--keepalive-timer )
( setq ein:notebooklist--keepalive-timer nil ) )
2017-01-31 10:44:04 -06:00
2015-02-10 14:53:08 -06:00
( defun* ein:notebooklist-url-retrieve-callback ( content )
2012-05-12 00:59:15 +02:00
" Called via `ein:notebooklist-open' . "
2015-02-10 14:53:08 -06:00
( let ( ( url-or-port ( ein:$content-url-or-port content ) )
( path ( ein:$content-path content ) )
( ipy-version ( ein:$content-ipython-version content ) )
( data ( ein:$content-raw-content content ) ) )
2016-04-15 16:08:53 -05:00
( when ( >= ipy-version 3 )
( ein:query-kernelspecs url-or-port ) )
2015-02-10 14:53:08 -06:00
( with-current-buffer ( ein:notebooklist-get-buffer url-or-port )
( let ( ( already-opened-p ( ein:notebooklist-list-get url-or-port ) )
( orig-point ( point ) ) )
( setq ein:%notebooklist%
( make-ein:$notebooklist :url-or-port url-or-port
:path path
:data data
:api-version ipy-version ) )
( ein:notebooklist-list-add ein:%notebooklist% )
2016-04-15 16:08:53 -05:00
( if ( < ipy-version 3 )
( ein:notebooklist-render-ipy2 )
( ein:notebooklist-render ) )
2015-02-10 14:53:08 -06:00
( goto-char orig-point )
2017-10-21 22:07:50 +09:00
( ein:log 'info " Opened notebook list at %s with path %s. " url-or-port path )
2015-02-10 14:53:08 -06:00
( unless already-opened-p
( run-hooks 'ein:notebooklist-first-open-hook ) )
2017-02-15 19:33:35 -06:00
( when ein:enable-keepalive
( ein:notebooklist-enable-keepalive ( ein:$content-url-or-port content ) ) )
2015-02-10 14:53:08 -06:00
( current-buffer ) ) ) ) )
2012-05-12 00:34:00 +02:00
2014-09-11 20:04:00 -05:00
( defun* ein:notebooklist-open-error ( url-or-port path
2012-12-29 17:44:49 +01:00
&key symbol-status response
2012-06-26 19:30:35 +02:00
&allow-other-keys )
2012-12-29 17:44:49 +01:00
( ein:log 'verbose
" Error thrown: %S " ( request-response-error-thrown response ) )
2012-06-26 19:30:35 +02:00
( ein:log 'error
2014-09-11 20:04:00 -05:00
" Error (%s) while opening notebook list with path %s at the server %s. "
symbol-status path url-or-port ) )
2012-06-26 19:30:35 +02:00
2012-09-01 20:51:55 +02:00
;;;###autoload
2015-01-13 06:40:15 -06:00
( defun ein:notebooklist-reload ( &optional notebooklist )
2012-05-13 05:18:38 +02:00
" Reload current Notebook list. "
( interactive )
2015-01-13 06:40:15 -06:00
( unless notebooklist
( setq notebooklist ein:%notebooklist% ) )
( ein:notebooklist-open ( ein:$notebooklist-url-or-port notebooklist )
( ein:$notebooklist-path notebooklist ) t ) )
2012-05-13 05:18:38 +02:00
2012-06-26 17:03:36 +02:00
( defun ein:notebooklist-refresh-related ( )
" Reload notebook list in which current notebook locates.
This function is called via ` ein:notebook-after-rename-hook '. "
2015-01-13 06:40:15 -06:00
( ein:notebooklist-open ( ein:$notebook-url-or-port ein:%notebook% )
( ein:$notebook-notebook-path ein:%notebook% ) t ) )
2012-06-26 17:03:36 +02:00
( add-hook 'ein:notebook-after-rename-hook 'ein:notebooklist-refresh-related )
2015-02-10 14:53:08 -06:00
( defun ein:notebooklist-open-notebook ( nblist path &optional callback cbargs )
2014-10-17 16:44:04 -05:00
( ein:notebook-open ( ein:$notebooklist-url-or-port nblist )
2015-02-10 14:53:08 -06:00
path
2016-04-15 16:08:53 -05:00
nil
2015-02-10 14:53:08 -06:00
callback
cbargs ) )
2012-05-18 02:23:30 +02:00
2017-04-20 07:47:05 -05:00
( defun ein:notebooklist-open-file ( url-or-port path )
( ein:file-open url-or-port
path ) )
2017-04-02 14:33:56 -05:00
;;;###autoload
( defun ein:notebooklist-upload-file ( upload-path )
( interactive " fSelect file to upload: " )
( unless ein:%notebooklist%
( error " Only works when called from an ein:notebooklist buffer. " ) )
( let ( ( nb-path ( ein:$notebooklist-path ein:%notebooklist% ) ) )
( ein:content-upload nb-path upload-path ) ) )
2012-09-01 20:51:55 +02:00
;;;###autoload
2016-01-13 07:52:02 -06:00
( defun ein:notebooklist-new-notebook ( &optional url-or-port kernelspec path callback cbargs )
2012-06-11 14:13:57 +02:00
" Ask server to create a new notebook and open it in a new buffer. "
2016-01-13 07:52:02 -06:00
( interactive ( list ( ein:notebooklist-ask-url-or-port )
2017-04-02 14:33:56 -05:00
( completing-read
" Select kernel [default]: "
( ein:list-available-kernels ( ein:$notebooklist-url-or-port ein:%notebooklist% ) ) nil t nil nil " default " nil ) ) )
2014-12-04 13:52:36 -06:00
( let ( ( path ( or path ( ein:$notebooklist-path ( or ein:%notebooklist%
( ein:notebooklist-list-get url-or-port ) ) ) ) )
( version ( ein:$notebooklist-api-version ( or ein:%notebooklist%
( ein:notebooklist-list-get url-or-port ) ) ) ) )
2014-09-19 09:17:12 -05:00
( ein:log 'info " Creating a new notebook at %s... " path )
( unless url-or-port
( setq url-or-port ( ein:$notebooklist-url-or-port ein:%notebooklist% ) ) )
( assert url-or-port nil
( concat " URL-OR-PORT is not given and the current buffer "
" is not the notebook list buffer. " ) )
( let ( ( url ( ein:notebooklist-new-url url-or-port
2014-11-07 19:28:09 -06:00
version
2014-09-19 09:17:12 -05:00
path ) ) )
( ein:query-singleton-ajax
( list 'notebooklist-new-notebook url-or-port path )
url
:type " POST "
2015-01-16 22:01:54 -06:00
:data ( json-encode ' ( ( :type . " notebook " ) ) )
2014-12-04 13:52:36 -06:00
:parser #' ein:json-read
;; (lambda ()
;; (ein:html-get-data-in-body-tag "data-notebook-id"))
2014-09-19 09:17:12 -05:00
:error ( apply-partially #' ein:notebooklist-new-notebook-error
url-or-port path callback cbargs )
:success ( apply-partially #' ein:notebooklist-new-notebook-callback
2016-01-13 07:52:02 -06:00
url-or-port kernelspec path callback cbargs ) ) ) ) )
2012-12-29 17:17:39 +01:00
( defun* ein:notebooklist-new-notebook-callback ( url-or-port
2016-03-01 16:02:00 -06:00
kernelspec
2014-09-19 09:17:12 -05:00
path
2012-12-29 17:17:39 +01:00
callback
cbargs
&key
2012-12-29 17:52:05 +01:00
data
&allow-other-keys
&aux
( no-popup t ) )
2015-02-10 14:53:08 -06:00
( ein:log 'info " Creating a new notebook (%s)... Done. " path )
2014-12-04 13:52:36 -06:00
( if data
( let ( ( name ( plist-get data :name ) )
( path ( plist-get data :path ) ) )
2015-03-25 09:52:16 -05:00
( if ( = ( ein:query-ipython-version url-or-port ) 2 )
( if ( string= path " " )
( setq path name )
( setq path ( format " %s/%s " path name ) ) ) )
2016-01-13 07:52:02 -06:00
( ein:notebook-open url-or-port path kernelspec callback cbargs ) )
2012-12-29 17:52:05 +01:00
( ein:log 'info ( concat " Oops. EIN failed to open new notebook. "
" Please find it in the notebook list. " ) )
( setq no-popup nil ) )
;; reload or open notebook list
2014-09-19 09:17:12 -05:00
( ein:notebooklist-open url-or-port path no-popup ) )
2012-05-26 19:51:57 +02:00
2012-09-06 23:46:29 +02:00
( defun* ein:notebooklist-new-notebook-error
2012-12-29 17:44:49 +01:00
( url-or-port callback cbargs
&key response &allow-other-keys
&aux
( no-popup t )
( error ( request-response-error-thrown response ) )
2013-01-10 19:10:59 +01:00
( dest ( request-response-url response ) ) )
2012-09-06 23:46:29 +02:00
( ein:log 'verbose
2013-01-10 19:10:59 +01:00
" NOTEBOOKLIST-NEW-NOTEBOOK-ERROR url-or-port: %S; error: %S; dest: %S "
url-or-port error dest )
( ein:log 'error
" Failed to open new notebook (error: %S). \
You may find the new one in the notebook list. " error)
( setq no-popup nil )
2012-12-29 17:52:05 +01:00
( ein:notebooklist-open url-or-port no-popup ) )
2012-09-06 23:46:29 +02:00
2012-09-01 20:51:55 +02:00
;;;###autoload
2016-03-22 07:47:11 -05:00
( defun ein:notebooklist-new-notebook-with-name ( name kernelspec url-or-port &optional path )
2012-06-08 12:59:14 +02:00
" Open new notebook and rename the notebook. "
2012-09-05 14:51:35 +02:00
( interactive ( let* ( ( url-or-port ( or ( ein:get-url-or-port )
( ein:default-url-or-port ) ) )
2016-03-22 07:47:11 -05:00
( kernelspec ( completing-read
" Select kernel [default]: "
( ein:list-available-kernels url-or-port ) nil t nil nil " default " nil ) )
2016-01-13 07:52:02 -06:00
( name ( read-from-minibuffer
( format " Notebook name (at %s): " url-or-port ) ) ) )
( list name kernelspec url-or-port ) ) )
2015-03-25 09:52:16 -05:00
( let ( ( path ( or path ( ein:$notebooklist-path
( or ein:%notebooklist%
( ein:get-notebook )
( gethash url-or-port ein:notebooklist-map ) ) ) ) ) )
2014-10-17 16:44:04 -05:00
( ein:notebooklist-new-notebook
url-or-port
2016-01-13 07:52:02 -06:00
kernelspec
2014-10-17 16:44:04 -05:00
path
( lambda ( notebook created name )
( assert created )
( with-current-buffer ( ein:notebook-buffer notebook )
( ein:notebook-rename-command name )
;; As `ein:notebook-open' does not call `pop-to-buffer' when
;; callback is specified, `pop-to-buffer' must be called here:
( pop-to-buffer ( current-buffer ) ) ) )
( list name ) ) ) )
2012-06-08 12:59:14 +02:00
2015-02-10 14:53:08 -06:00
( defun ein:notebooklist-delete-notebook-ask ( path )
( when ( y-or-n-p ( format " Delete notebook %s? " path ) )
( ein:notebooklist-delete-notebook path ) ) )
2012-05-13 06:51:26 +02:00
2015-02-10 14:53:08 -06:00
( defun ein:notebooklist-delete-notebook ( path )
( ein:log 'info " Deleting notebook %s... " path )
2012-06-20 21:01:58 +02:00
( ein:query-singleton-ajax
( list 'notebooklist-delete-notebook
2015-02-10 14:53:08 -06:00
( ein:$notebooklist-url-or-port ein:%notebooklist% ) path )
2012-05-26 19:01:39 +02:00
( ein:notebook-url-from-url-and-id
2012-08-18 22:31:15 +02:00
( ein:$notebooklist-url-or-port ein:%notebooklist% )
2014-10-17 16:44:04 -05:00
( ein:$notebooklist-api-version ein:%notebooklist% )
2015-02-10 14:53:08 -06:00
path )
2012-05-26 19:01:39 +02:00
:type " DELETE "
2017-09-30 21:34:00 +09:00
:success ( apply-partially ( lambda ( path notebook-list &rest ignore )
2012-12-29 17:17:39 +01:00
( ein:log 'info
2015-02-10 14:53:08 -06:00
" Deleting notebook %s... Done. " path )
2017-09-30 21:34:00 +09:00
( ein:notebooklist-reload notebook-list ) )
path ein:%notebooklist% ) ) )
2012-05-12 00:59:15 +02:00
2015-12-04 14:15:41 -06:00
;; Because MinRK wants me to suffer (not really, I love MinRK)...
2014-11-12 06:38:02 -06:00
( defun ein:get-actual-path ( path )
( ein:aif ( cl-position ?/ path :from-end t )
( substring path 0 it )
" " ) )
2014-12-09 10:41:53 -06:00
( defun generate-breadcrumbs ( path )
" Given notebooklist path, generate alist of breadcrumps of form (name . path). "
( let* ( ( paths ( split-string path " / " t ) )
( current-path " / " )
( pairs ( list ( cons " Home " " " ) ) ) )
( dolist ( p paths pairs )
2015-09-14 13:16:49 -05:00
( setf current-path ( concat current-path " / " p )
2014-12-09 10:41:53 -06:00
pairs ( append pairs ( list ( cons p current-path ) ) ) ) ) ) )
2016-04-15 16:08:53 -05:00
( defun ein:notebooklist-render-ipy2 ( )
" Render notebook list for IPython 2.x sessions.
Notebook list data is passed via the buffer local variable
` ein:notebooklist-data '. "
( kill-all-local-variables )
( let ( ( inhibit-read-only t ) )
( erase-buffer ) )
( remove-overlays )
2018-03-27 22:34:19 -07:00
( render-header-ipy2 )
2018-03-31 13:58:01 -07:00
( render-directory-ipy2 )
2018-03-27 22:34:19 -07:00
( ein:notebooklist-mode )
2018-04-22 10:22:11 -05:00
( widget-setup ) )
2018-04-22 20:57:01 -05:00
( defun* ein:nblist--sort-group ( group by-param order )
2018-04-22 10:22:11 -05:00
( sort group #' ( lambda ( x y )
2018-05-04 15:07:32 -04:00
( cond ( ( eql order :ascending )
2018-04-22 20:57:01 -05:00
( string-lessp ( plist-get x by-param )
( plist-get y by-param ) ) )
2018-05-04 15:07:32 -04:00
( ( eql order :descending )
2018-04-22 20:57:01 -05:00
( string-greaterp ( plist-get x by-param )
( plist-get y by-param ) ) ) ) ) ) )
( defun ein:notebooklist--order-data ( nblist-data sort-param sort-order )
2018-03-27 22:34:19 -07:00
" Try to sanely sort the notebooklist data for the current path. "
( let* ( ( groups ( -group-by #' ( lambda ( x ) ( plist-get x :type ) )
nblist-data ) )
2018-04-22 20:57:01 -05:00
( dirs ( ein:nblist--sort-group ( cdr ( assoc " directory " groups ) )
sort-param
sort-order ) )
( nbs ( ein:nblist--sort-group ( cdr ( assoc " notebook " groups ) )
sort-param
sort-order ) )
2018-04-22 10:22:11 -05:00
( files ( ein:nblist--sort-group ( -flatten-n 1 ( -map #' cdr ( -group-by
#' ( lambda ( x ) ( car ( last ( s-split " \\ . " ( plist-get x :name ) ) ) ) )
2018-04-22 20:57:01 -05:00
( cdr ( assoc " file " groups ) ) ) ) )
sort-param
sort-order ) ) )
2018-03-27 22:34:19 -07:00
( -concat dirs nbs files ) ) )
2018-04-22 10:22:11 -05:00
( defun render-header-ipy2 ( )
" Render the header (for ipython2). "
2016-04-15 16:08:53 -05:00
;; Create notebook list
( widget-insert ( format " IPython %s Notebook list \n \n " ( ein:$notebooklist-api-version ein:%notebooklist% ) ) )
2018-03-27 22:34:19 -07:00
2016-04-15 16:08:53 -05:00
( let ( ( breadcrumbs ( generate-breadcrumbs ( ein:$notebooklist-path ein:%notebooklist% ) ) ) )
( dolist ( p breadcrumbs )
( lexical-let ( ( name ( car p ) )
( path ( cdr p ) ) )
( widget-insert " | " )
( widget-create
'link
:notify ( lambda ( &rest ignore ) ( ein:notebooklist-open
( ein:$notebooklist-url-or-port ein:%notebooklist% )
path ) )
name ) ) )
( widget-insert " | \n \n " ) )
2018-03-27 22:34:19 -07:00
2016-04-15 16:08:53 -05:00
( widget-create
'link
:notify ( lambda ( &rest ignore ) ( ein:notebooklist-new-notebook
( ein:$notebooklist-url-or-port ein:%notebooklist% ) ) )
" New Notebook " )
( widget-insert " " )
( widget-create
'link
:notify ( lambda ( &rest ignore ) ( ein:notebooklist-reload ) )
" Reload List " )
( widget-insert " " )
( widget-create
'link
:notify ( lambda ( &rest ignore )
( browse-url
( ein:url ( ein:$notebooklist-url-or-port ein:%notebooklist% ) ) ) )
" Open In Browser " )
2018-04-22 10:22:11 -05:00
( widget-insert " \n " ) )
2017-09-12 16:22:19 -05:00
2018-04-22 10:22:11 -05:00
( defun render-header ( )
" Render the header (for ipython>=3). "
2012-05-07 14:41:15 +02:00
;; Create notebook list
2016-11-05 17:49:52 -05:00
( widget-insert
( if ( < ( ein:$notebooklist-api-version ein:%notebooklist% ) 4 )
2017-11-07 15:14:45 -06:00
( format " IPython v%s Notebook list (%s) \n \n " ( ein:$notebooklist-api-version ein:%notebooklist% ) ( ein:$notebooklist-url-or-port ein:%notebooklist% ) )
( format " Jupyter v%s Notebook list (%s) \n \n " ( ein:$notebooklist-api-version ein:%notebooklist% ) ( ein:$notebooklist-url-or-port ein:%notebooklist% ) ) ) )
2018-03-25 12:32:31 -07:00
2014-12-09 10:41:53 -06:00
( let ( ( breadcrumbs ( generate-breadcrumbs ( ein:$notebooklist-path ein:%notebooklist% ) ) ) )
( dolist ( p breadcrumbs )
( lexical-let ( ( name ( car p ) )
( path ( cdr p ) ) )
( widget-insert " | " )
( widget-create
'link
:notify ( lambda ( &rest ignore ) ( ein:notebooklist-open
2018-04-22 10:22:11 -05:00
( ein:$notebooklist-url-or-port ein:%notebooklist% )
path ) )
2014-12-09 10:41:53 -06:00
name ) ) )
2015-05-28 11:56:40 -05:00
( widget-insert " | \n \n " ) )
2018-03-27 22:34:19 -07:00
2016-03-23 12:31:47 -05:00
( lexical-let* ( ( kernels ( ein:list-available-kernels ( ein:$notebooklist-url-or-port ein:%notebooklist% ) ) )
( default-kernel ( ein:get-kernelspec ( ein:$notebooklist-url-or-port ein:%notebooklist% ) ( first kernels ) ) ) )
2018-03-27 22:34:19 -07:00
2016-01-13 07:52:02 -06:00
( widget-create
'link
2016-03-01 16:02:00 -06:00
:notify ( lambda ( &rest ignore ) ( ein:notebooklist-new-notebook
( ein:$notebooklist-url-or-port ein:%notebooklist% )
default-kernel ) )
2016-01-13 07:52:02 -06:00
" New Notebook " )
( widget-insert " " )
( widget-create
'link
:notify ( lambda ( &rest ignore ) ( ein:notebooklist-reload ) )
" Reload List " )
( widget-insert " " )
2018-05-20 08:42:42 -05:00
( widget-create
'link
:notify ( lambda ( &rest ignore ) ( ein:notebooklist-refresh-kernelspecs ) )
" Query Kernelspecs " )
( widget-insert " " )
2016-01-13 07:52:02 -06:00
( widget-create
'link
:notify ( lambda ( &rest ignore )
2016-04-15 16:08:53 -05:00
( browse-url
( ein:url ( ein:$notebooklist-url-or-port ein:%notebooklist% ) ) ) )
2016-01-13 07:52:02 -06:00
" Open In Browser " )
2018-03-27 22:34:19 -07:00
2016-01-13 08:30:15 -06:00
( widget-insert " \n \n Create New Notebooks Using Kernel: \n " )
2016-01-13 07:52:02 -06:00
( let* ( ( radio-widget ( widget-create 'radio-button-choice
2016-12-22 14:04:51 -06:00
;; :value (car (first kernels))
;; :format (format "%s\n" (cdr (first kernels)))
:notify ( lambda ( widget &rest ignore )
( setq default-kernel
( ein:get-kernelspec ( ein:$notebooklist-url-or-port ein:%notebooklist% ) ( widget-value widget ) ) )
( message " New notebooks will be started using the %s kernel. "
( widget-value widget ) ) ) ) ) )
2016-01-13 07:52:02 -06:00
( dolist ( k kernels )
2016-12-22 14:04:51 -06:00
( widget-radio-add-item radio-widget ( list 'item :value ( car k )
:format ( format " %s \n " ( cdr k ) ) ) ) ) ) )
2018-04-22 10:22:11 -05:00
( widget-insert " \n " ) )
2018-03-25 12:32:31 -07:00
2018-04-22 10:22:11 -05:00
( defun render-opened-notebooks ( )
2018-03-25 12:32:31 -07:00
" Render the opened notebooks section (for ipython>=3). "
2018-04-22 10:22:11 -05:00
;; Opened Notebooks Section
( widget-insert " \n ---------- All Opened Notebooks ---------- \n \n " )
( loop for buffer in ( ein:notebook-opened-buffers )
do ( progn ( widget-create
'link
:notify ( lexical-let ( ( buffer buffer ) )
( lambda ( &rest ignore )
( switch-to-buffer buffer ) ) )
" Open " )
( widget-create
'link
:notify ( lexical-let ( ( buffer buffer ) )
( lambda ( &rest ignore )
( kill-buffer buffer )
( run-at-time 1 nil
#' ein:notebooklist-reload
ein:%notebooklist% ) ) )
" Close " )
( widget-insert " : " ( buffer-name buffer ) )
( widget-insert " \n " ) ) ) )
2018-03-25 12:32:31 -07:00
2018-03-31 14:38:25 -07:00
( defun render-directory-ipy3 ( )
" Call render-direcory with ipy-at-least-3 true. "
2018-04-22 10:22:11 -05:00
( render-directory t ) )
2018-03-31 14:38:25 -07:00
( defun render-directory-ipy2 ( )
" Call render-direcory with ipy-at-least-3 false. "
2018-04-22 10:22:11 -05:00
( render-directory nil ) )
2018-03-31 14:38:25 -07:00
2018-04-22 20:57:01 -05:00
( defun ein:format-nbitem-data ( name last-modified )
( let ( ( dt ( date-to-time last-modified ) ) )
2018-04-23 17:33:13 -04:00
( format " %-40s%+20s " name
2018-05-25 11:43:39 -04:00
( ein:format-time-string ein:notebooklist-date-format dt ) ) ) )
2018-04-22 20:57:01 -05:00
2018-03-31 14:38:25 -07:00
( defun render-directory ( ipy-at-least-3 )
" Render directory.
IPY-AT-LEAST-3 used to keep track of version. "
2018-04-22 10:22:11 -05:00
( widget-insert " \n ------------------------------------------ \n \n " )
( unless ipy-at-least-3
2018-04-22 20:57:01 -05:00
( let ( api-version ( ein:$notebooklist-api-version ein:%notebooklist% ) ) ) )
( let ( ( sessions ( make-hash-table :test 'equal ) ) )
2018-04-22 10:22:11 -05:00
( ein:content-query-sessions sessions ( ein:$notebooklist-url-or-port ein:%notebooklist% ) t )
( sit-for 0.2 ) ;; FIXME: What is the optimum number here?
2018-05-04 15:07:32 -04:00
( ein:make-sorting-widget " Sort by " ein:notebooklist-sort-field )
( ein:make-sorting-widget " In Order " ein:notebooklist-sort-order )
2018-04-22 20:57:01 -05:00
( widget-insert " \n " )
( loop for note in ( ein:notebooklist--order-data ( ein:$notebooklist-data ein:%notebooklist% )
2018-05-04 15:07:32 -04:00
ein:notebooklist-sort-field
ein:notebooklist-sort-order )
2016-08-31 10:04:06 -05:00
for urlport = ( ein:$notebooklist-url-or-port ein:%notebooklist% )
for name = ( plist-get note :name )
for path = ( plist-get note :path )
2018-04-22 20:57:01 -05:00
for last-modified = ( plist-get note :last_modified )
2018-03-31 13:58:01 -07:00
;; (cond ((= 2 api-version)
;; (plist-get note :path))
;; ((= 3 api-version)
;; (ein:get-actual-path (plist-get note :path))))
2016-08-31 10:04:06 -05:00
for type = ( plist-get note :type )
for opened-notebook-maybe = ( ein:notebook-get-opened-notebook urlport path )
do ( widget-insert " " )
if ( string= type " directory " )
do ( progn ( widget-create
'link
:notify ( lexical-let ( ( urlport urlport )
( path name ) )
( lambda ( &rest ignore )
( ein:notebooklist-open urlport
( ein:url ( ein:$notebooklist-path ein:%notebooklist% )
path ) ) ) )
" Dir " )
( widget-insert " : " name )
( widget-insert " \n " ) )
2018-03-31 14:38:25 -07:00
if ( and ( string= type " file " ) ipy-at-least-3 )
2018-03-31 13:58:01 -07:00
do ( progn ( widget-create
'link
:notify ( lexical-let ( ( urlport urlport )
( path path ) )
( lambda ( &rest ignore )
( ein:notebooklist-open-file urlport path ) ) )
" Open " )
2018-04-22 20:57:01 -05:00
( widget-insert " ------ " )
2018-03-31 13:58:01 -07:00
( widget-create
'link
:notify ( lexical-let ( ( path path ) )
( lambda ( &rest ignore )
( message " [EIN]: NBlist delete file command. Implement me! " ) ) )
" Delete " )
2018-04-22 20:57:01 -05:00
( widget-insert " : " ( ein:format-nbitem-data name last-modified ) )
2018-03-31 13:58:01 -07:00
( widget-insert " \n " ) )
2016-08-31 10:04:06 -05:00
if ( string= type " notebook " )
do ( progn ( widget-create
'link
:notify ( lexical-let ( ( name name )
( path path ) )
( lambda ( &rest ignore )
( run-at-time 3 nil
#' ein:notebooklist-reload ein:%notebooklist% ) ;; TODO using deferred better?
( ein:notebooklist-open-notebook
ein:%notebooklist% path ) ) )
" Open " )
( widget-insert " " )
2018-04-22 20:57:01 -05:00
( if ( gethash path sessions )
( widget-create
'link
:notify ( lexical-let ( ( session ( car ( gethash path sessions ) ) )
( nblist ein:%notebooklist% ) )
( lambda ( &rest ignore )
( run-at-time 1 nil
#' ein:notebooklist-reload
ein:%notebooklist% )
( ein:kernel-kill ( make-ein:$kernel :url-or-port ( ein:$notebooklist-url-or-port nblist )
:session-id session ) ) ) )
" Stop " )
( widget-insert " ------ " ) )
( widget-insert " " )
2016-08-31 10:04:06 -05:00
( widget-create
'link
:notify ( lexical-let ( ( path path ) )
( lambda ( &rest ignore )
( ein:notebooklist-delete-notebook-ask
path ) ) )
" Delete " )
2018-04-22 20:57:01 -05:00
( widget-insert " : " ( ein:format-nbitem-data name last-modified ) )
2018-04-22 10:22:11 -05:00
( widget-insert " \n " ) ) ) ) )
2018-03-25 12:32:31 -07:00
2018-03-31 13:58:01 -07:00
2018-03-25 12:32:31 -07:00
( defun ein:notebooklist-render ( )
" Render notebook list widget.
Notebook list data is passed via the buffer local variable
` ein:notebooklist-data '. "
( kill-all-local-variables )
( let ( ( inhibit-read-only t ) )
( erase-buffer ) )
( remove-overlays )
2018-03-25 13:30:50 -07:00
( mapc ( lambda ( fn ) ( apply fn ' ( ) ) )
2018-04-22 10:22:11 -05:00
ein:notebook-list-render-order )
2018-03-25 12:32:31 -07:00
2012-05-15 03:41:08 +02:00
( ein:notebooklist-mode )
2012-05-07 14:41:15 +02:00
( widget-setup ) )
2018-03-25 13:42:35 -07:00
;;;###autoload
2012-07-12 01:05:37 +02:00
( defun ein:notebooklist-list-notebooks ( )
2018-03-25 13:42:35 -07:00
" Return a list of notebook path (NBPATH). Each element NBPATH
is a string of the format \"URL-OR-PORT/NOTEBOOK-NAME\". "
2012-07-12 01:05:37 +02:00
( apply #' append
( loop for nblist in ( ein:notebooklist-list )
for url-or-port = ( ein:$notebooklist-url-or-port nblist )
2015-02-10 14:53:08 -06:00
for api-version = ( ein:$notebooklist-api-version nblist )
2012-07-12 01:05:37 +02:00
collect
2015-12-04 14:15:41 -06:00
( loop for note in ( ein:get-content-hierarchy url-or-port )
2015-02-10 14:53:08 -06:00
collect ( format " %s/%s " url-or-port
( ein:$content-path note )
) )
2015-02-12 09:20:34 -06:00
;; (if (= api-version 3)
;; (loop for note in (ein:make-content-hierarchy "" url-or-port)
;; collect (format "%s/%s" url-or-port
;; (ein:$content-path note)
;; ))
;; (loop for note in (ein:$notebooklist-data nblist)
;; collect (format "%s/%s"
;; url-or-port
;; (plist-get note :name))))
) ) )
2012-07-12 01:05:37 +02:00
2014-12-03 19:44:02 -06:00
;;FIXME: Code below assumes notebook is in root directory - need to do a better
;; job listing notebooks in subdirectories and parsing out the path.
2012-09-01 20:51:55 +02:00
;;;###autoload
2012-07-12 02:04:50 +02:00
( defun ein:notebooklist-open-notebook-global ( nbpath &optional callback cbargs )
2012-07-12 01:05:37 +02:00
" Choose notebook from all opened notebook list and open it.
Notebook is specified by a string NBPATH whose format is
2012-07-12 02:04:50 +02:00
\"URL-OR-PORT/NOTEBOOK-NAME\".
When used in lisp, CALLBACK and CBARGS are passed to ` ein:notebook-open '. "
2012-06-05 14:54:18 +02:00
( interactive
( list ( completing-read
" Open notebook [URL-OR-PORT/NAME]: "
2012-07-12 01:05:37 +02:00
( ein:notebooklist-list-notebooks ) ) ) )
2015-02-10 14:53:08 -06:00
( let* ( ( url-or-port ( substring nbpath 0 ( cl-position ?/ nbpath ) ) )
( path ( substring nbpath ( 1+ ( cl-position ?/ nbpath ) ) ) ) )
2012-06-05 14:54:18 +02:00
( when ( and ( stringp url-or-port )
( string-match " ^[0-9]+$ " url-or-port ) )
( setq url-or-port ( string-to-number url-or-port ) ) )
2016-01-13 07:52:02 -06:00
( ein:notebook-open url-or-port path nil callback cbargs )
2014-12-03 19:44:02 -06:00
( ein:log 'info " Notebook '%s' not found " nbpath ) ) )
2012-06-05 14:54:18 +02:00
2012-09-01 20:51:55 +02:00
;;;###autoload
2012-08-26 22:12:49 +02:00
( defun ein:notebooklist-load ( &optional url-or-port )
" Load notebook list but do not pop-up the notebook list buffer.
For example, if you want to load notebook list when Emacs starts,
add this in the Emacs initialization file::
( add-to-hook 'after-init-hook 'ein:notebooklist-load )
or even this ( if you want fast Emacs start-up ) : :
;; load notebook list if Emacs is idle for 3 sec after start-up
( run-with-idle-timer 3 nil #' ein:notebooklist-load )
You should setup ` ein:url-or-port ' or ` ein:default-url-or-port '
in order to make this code work.
See also:
` ein:connect-to-default-notebook ', ` ein:connect-default-notebook '. "
( ein:notebooklist-open url-or-port t ) )
2012-09-05 17:27:29 +02:00
( defun ein:notebooklist-find-server-by-notebook-name ( name )
2015-02-10 14:53:08 -06:00
" Find a notebook named NAME and return a list (URL-OR-PORT PATH). "
2012-09-05 17:27:29 +02:00
( loop named outer
for nblist in ( ein:notebooklist-list )
for url-or-port = ( ein:$notebooklist-url-or-port nblist )
2015-02-10 14:53:08 -06:00
for ipython-version = ( ein:$notebooklist-api-version nblist )
do
2018-03-08 14:08:45 -06:00
( if ( >= ipython-version 3 )
2015-02-10 14:53:08 -06:00
( loop for note in ( ein:make-content-hierarchy " " url-or-port )
when ( equal ( ein:$content-name note ) name )
do ( return-from outer
( list url-or-port ( ein:$content-path note ) ) ) )
( loop for note in ( ein:$notebooklist-data nblist )
when ( equal ( plist-get note :name ) name )
do ( return-from outer
( list url-or-port
( format " %s/%s " ( plist-get note :path ) ( plist-get note :name ) ) ) ) ) ) ) )
2012-09-05 17:27:29 +02:00
2012-09-05 17:52:46 +02:00
( defun ein:notebooklist-open-notebook-by-file-name
2012-09-05 18:02:35 +02:00
( &optional filename noerror buffer-callback )
2012-09-05 17:27:29 +02:00
" Find the notebook named as same as the current file in the servers.
Open the notebook if found. Note that this command will *not*
upload the current file to the server.
. . When FILENAME is unspecified the variable ` buffer-file-name '
2012-09-05 17:52:46 +02:00
is used instead. Set NOERROR to non- ` nil ' to suppress errors.
2012-09-05 18:02:35 +02:00
BUFFER-CALLBACK is called after opening notebook with the
current buffer as the only one argument. "
2012-09-05 17:27:29 +02:00
( interactive ( progn ( assert buffer-file-name nil " Not visiting a file. " )
nil ) )
( unless filename ( setq filename buffer-file-name ) )
( assert filename nil " No file found. " )
( let* ( ( name ( file-name-sans-extension
( file-name-nondirectory ( or filename ) ) ) )
2012-09-05 18:02:35 +02:00
( found ( ein:notebooklist-find-server-by-notebook-name name ) )
( callback ( lambda ( -ignore-1- -ignore-2- buffer buffer-callback )
( ein:notebook-pop-to-current-buffer ) ; default
( when ( buffer-live-p buffer )
( funcall buffer-callback buffer ) ) ) )
( cbargs ( list ( current-buffer ) ( or buffer-callback #' ignore ) ) ) )
2012-09-05 20:33:21 +02:00
( unless noerror
( assert found nil " No server has notebook named: %s " name ) )
2015-02-10 14:53:08 -06:00
( destructuring-bind ( url-or-port path ) found
2016-01-13 07:52:02 -06:00
( ein:notebook-open url-or-port path nil callback cbargs ) ) ) )
2012-09-05 17:52:46 +02:00
2012-09-05 18:02:35 +02:00
( defvar ein:notebooklist-find-file-buffer-callback #' ignore )
2012-09-05 17:52:46 +02:00
( defun ein:notebooklist-find-file-callback ( )
2012-09-05 18:02:35 +02:00
" A callback function for `find-file-hook' to open notebook.
FIMXE: document how to use ` ein:notebooklist-find-file-callback '
when I am convinced with the API. "
2012-09-05 17:52:46 +02:00
( ein:and-let* ( ( filename buffer-file-name )
( ( string-match-p " \\ .ipynb$ " filename ) ) )
2012-09-05 18:02:35 +02:00
( ein:notebooklist-open-notebook-by-file-name
filename t ein:notebooklist-find-file-buffer-callback ) ) )
2012-09-05 17:27:29 +02:00
2012-12-17 16:51:31 +01:00
;;; Login
2016-12-27 12:03:05 -05:00
;;;###autoload
2017-02-17 15:06:59 -06:00
( defun ein:notebooklist-login ( url-or-port password &optional retry-p )
2012-12-17 16:51:31 +01:00
" Login to IPython notebook server. "
( interactive ( list ( ein:notebooklist-ask-url-or-port )
2012-12-17 17:55:30 +01:00
( read-passwd " Password: " ) ) )
2017-10-21 18:47:38 +09:00
( ein:log 'debug " NOTEBOOKLIST-LOGIN: %s:%s " url-or-port password )
2012-12-17 16:51:31 +01:00
( ein:query-singleton-ajax
( list 'notebooklist-login url-or-port )
( ein:url url-or-port " login " )
:type " POST "
2012-12-17 23:15:21 +01:00
:data ( concat " password= " ( url-hexify-string password ) )
2012-12-17 19:26:13 +01:00
:parser #' ein:notebooklist-login--parser
2017-02-17 15:06:59 -06:00
:error ( apply-partially #' ein:notebooklist-login--error url-or-port password retry-p )
2012-12-29 17:17:39 +01:00
:success ( apply-partially #' ein:notebooklist-login--success url-or-port ) ) )
2012-12-17 19:26:13 +01:00
( defun ein:notebooklist-login--parser ( )
( goto-char ( point-min ) )
2013-01-10 19:25:08 +01:00
( list :bad-page ( re-search-forward " <input type=.?password " nil t ) ) )
2012-12-17 19:26:13 +01:00
( defun ein:notebooklist-login--success-1 ( url-or-port )
( ein:log 'info " Login to %s complete. \
2012-12-17 16:51:31 +01:00
Now you can open notebook list by ` ein:notebooklist-open '. " url-or-port))
2012-12-17 19:26:13 +01:00
( defun ein:notebooklist-login--error-1 ( url-or-port )
( ein:log 'info " Failed to login to %s " url-or-port ) )
( defun* ein:notebooklist-login--success ( url-or-port &key
data
&allow-other-keys )
( if ( plist-get data :bad-page )
( ein:notebooklist-login--error-1 url-or-port )
( ein:notebooklist-login--success-1 url-or-port ) ) )
2013-01-09 05:51:25 +01:00
( defun* ein:notebooklist-login--error
2017-02-17 15:06:59 -06:00
( url-or-port password retry-p &key
2013-01-09 05:51:25 +01:00
data
symbol-status
response
&allow-other-keys
&aux
( response-status ( request-response-status-code response ) ) )
2017-02-17 15:06:59 -06:00
( if ( and ( eq response-status 403 )
( not retry-p ) )
( ein:notebooklist-login url-or-port password t ) )
2013-01-10 19:25:08 +01:00
( if ( or
;; workaround for url-retrieve backend
( and ( eq symbol-status 'timeout )
( equal response-status 302 )
( request-response-header response " set-cookie " ) )
;; workaround for curl backend
( and ( equal response-status 405 )
( ein:aand ( car ( request-response-history response ) )
( request-response-header it " set-cookie " ) ) ) )
2012-12-17 19:26:13 +01:00
( ein:notebooklist-login--success-1 url-or-port )
( ein:notebooklist-login--error-1 url-or-port ) ) )
2012-12-17 16:51:31 +01:00
2017-05-24 09:53:58 -05:00
;;;###autoload
( defun ein:notebooklist-change-url-port ( new-url-or-port )
" Update the ipython/jupyter notebook server URL for all the
notebooks currently opened from the current notebooklist buffer.
This function works by calling ` ein:notebook-update-url-or-port '
on all the notebooks opened from the current notebooklist. "
( interactive ( list ( ein:notebooklist-ask-url-or-port ) ) )
( unless ( eql major-mode 'ein:notebooklist-mode )
( error " This command needs to be called from within a notebooklist buffer. " ) )
2017-11-07 15:14:45 -06:00
( let* ( ( current-nblist ein:%notebooklist% )
( old-url ( ein:$notebooklist-url-or-port current-nblist ) )
( new-url-or-port new-url-or-port )
( open-nb ( ein:notebook-opened-notebooks #' ( lambda ( nb )
( equal ( ein:$notebook-url-or-port nb )
( ein:$notebooklist-url-or-port current-nblist ) ) ) ) ) )
( ein:notebooklist-open new-url-or-port " / " t )
( loop for x upfrom 0 by 1
until ( or ( get-buffer ( format ein:notebooklist-buffer-name-template new-url-or-port ) )
( = x 100 ) )
do ( sit-for 0.1 ) )
( dolist ( nb open-nb )
( ein:notebook-update-url-or-port new-url-or-port nb ) )
( kill-buffer ( ein:notebooklist-get-buffer old-url ) )
( ein:notebooklist-open new-url-or-port " / " nil ) ) )
( defun ein:notebooklist-change-url-port--deferred ( new-url-or-port )
2017-05-30 14:33:31 -05:00
( lexical-let* ( ( current-nblist ein:%notebooklist% )
2017-06-03 15:45:28 -05:00
( old-url ( ein:$notebooklist-url-or-port current-nblist ) )
2017-05-30 14:33:31 -05:00
( new-url-or-port new-url-or-port )
( open-nb ( ein:notebook-opened-notebooks #' ( lambda ( nb )
( equal ( ein:$notebook-url-or-port nb )
( ein:$notebooklist-url-or-port current-nblist ) ) ) ) ) )
2017-05-30 14:05:02 -05:00
( deferred:$
( deferred:next
2017-05-30 14:33:31 -05:00
( lambda ( )
2017-06-03 15:45:28 -05:00
( ein:notebooklist-open new-url-or-port " / " t )
2017-05-30 14:33:31 -05:00
( loop until ( get-buffer ( format ein:notebooklist-buffer-name-template new-url-or-port ) )
do ( sit-for 0.1 ) ) ) )
2017-05-30 14:05:02 -05:00
( deferred:nextc it
2017-05-30 14:33:31 -05:00
( lambda ( )
( dolist ( nb open-nb )
2017-06-03 15:45:28 -05:00
( ein:notebook-update-url-or-port new-url-or-port nb ) ) ) )
( deferred:nextc it
( lambda ( )
( kill-buffer ( ein:notebooklist-get-buffer old-url ) )
( ein:notebooklist-open new-url-or-port " / " nil ) ) ) ) ) )
2012-08-13 18:55:32 +02:00
;;; Generic getter
2017-05-24 09:53:58 -05:00
2012-08-13 18:55:32 +02:00
( defun ein:get-url-or-port--notebooklist ( )
2012-08-18 22:31:15 +02:00
( when ( ein:$notebooklist-p ein:%notebooklist% )
( ein:$notebooklist-url-or-port ein:%notebooklist% ) ) )
2012-08-13 18:55:32 +02:00
2012-05-15 03:41:08 +02:00
;;; Notebook list mode
2012-05-15 04:16:06 +02:00
( defun ein:notebooklist-prev-item ( ) ( interactive ) ( move-beginning-of-line 0 ) )
( defun ein:notebooklist-next-item ( ) ( interactive ) ( move-beginning-of-line 2 ) )
2016-09-23 10:37:48 -05:00
( defvar ein:notebooklist-mode-map
( let ( ( map ( make-sparse-keymap ) ) )
( set-keymap-parent map ( make-composed-keymap widget-keymap
special-mode-map ) )
( define-key map " \C -c \C -r " 'ein:notebooklist-reload )
( define-key map " p " 'ein:notebooklist-prev-item )
( define-key map " n " 'ein:notebooklist-next-item )
map )
" Keymap for ein:notebooklist-mode. " )
( easy-menu-define ein:notebooklist-menu ein:notebooklist-mode-map
" EIN Notebook List Mode Menu "
` ( " EIN Notebook List "
,@ ( ein:generate-menu
' ( ( " Reload " ein:notebooklist-reload )
( " New Notebook " ein:notebooklist-new-notebook )
( " New Notebook (with name) "
ein:notebooklist-new-notebook-with-name )
( " New Junk Notebook " ein:junk-new ) ) ) ) )
2012-05-15 03:41:08 +02:00
2016-09-19 09:02:35 -05:00
( defun ein:notebooklist-revert-wrapper ( &optional ignore-auto noconfirm preserve-modes )
( ein:notebooklist-reload ) )
( define-derived-mode ein:notebooklist-mode special-mode " ein:notebooklist "
" IPython notebook list mode.
Commands:
\\{ein:notebooklist-mode-map}} "
( set ( make-local-variable 'revert-buffer-function )
'ein:notebooklist-revert-wrapper ) )
2012-05-07 14:41:15 +02:00
( provide 'ein-notebooklist )
;;; ein-notebooklist.el ends here