[CHANGED] created mojo-mode minor mode. prefix all functions with mojo-.

This commit is contained in:
Sami Samhuri 2009-12-01 08:30:09 -08:00
parent 5855f51326
commit 057120c5e6
5 changed files with 493 additions and 56 deletions

63
README
View file

@ -9,8 +9,10 @@ Authors: Jonathan Arkell <jonnay@jonnay.net>
Overview
========
Mojo.el is an Emacs package that provides interactive functions to aid the
development of webOS apps.
Mojo.el is an Emacs package that provides interactive functions to aid
the development of webOS apps. There is a minor mode that can be
toggled with the command `mojo-mode'.
Latest version is available on github:
http://github.com/samsonjs/mojo.el
@ -32,21 +34,15 @@ Installation
mojo-project-directory, mojo-sdk-directory and mojo-build-directory
(Use M-x customize-group RET mojo RET)
(optional)
4. I recommend that you define a few keyboard shortcuts in your Emacs init
file. Maybe something like this:
(global-set-key [f2] mojo-generate-scene)
(global-set-key [f3] mojo-emulate)
(global-set-key [f4] mojo-package)
(global-set-key [f5] mojo-package-install-and-inspect)
Commands
========
The complete command list:
Code generation
---------------
mojo-generate
Generate a new Mojo application in the mojo-project-directory.
@ -54,6 +50,10 @@ The complete command list:
Generate a new Mojo scene for the application found by mojo-root.
(a.k.a. the current application)
Packaging and device/emulator interactions
------------------------------------------
mojo-emulate
Launch the palm emulator.
@ -71,13 +71,15 @@ The complete command list:
Remove the specified application. (defaults to current app id)
mojo-launch
Launch the specified application in the emulator. (defaults to current app id)
Launch the specified application in the emulator. (defaults to
current app id)
mojo-close
Close specified application. (defaults to current app id)
mojo-inspect
Run the dom inspector on the specified application. (defaults to current app id)
Run the dom inspector on the specified application. (defaults to
current app id)
mojo-hard-reset
Perform a hard reset, clearing all data.
@ -94,10 +96,43 @@ The complete command list:
mojo-target-emulator
Set the target device to the emulator.
mojo-toggle-target
Automatically change the target device from 'usb' to 'tcp' and vice
versa.
Quickly switch buffers
----------------------
mojo-switch-to-assistant
Switch to the corresponding assistant from any view file.
mojo-switch-to-view
Switch to the main view from an assistant.
mojo-switch-to-next-view
Switch to the next view file, alphabetically. Wraps around at the
end.
mojo-switch-to-appinfo
Switch to the appinfo.json file.
mojo-switch-to-sources
Switch to the sources.json file.
mojo-switch-to-index
Switch to the root index.html file.
mojo-switch-to-stylesheet
Switch to the main stylesheet.
Customizations
==============
Customizable options:
mojo-sdk-directory
Path to where the mojo SDK is. (default ok for windows and mac os x)
default = (case system-type

6
TODO
View file

@ -1,4 +1,8 @@
TODO
====
* Jump to related files: to assistant from view and vice versa
* Detect when inside a mojo project and load mojo-mode
* turn on and off debugging & logging
* switch to last visited view
* inject Mojo.Ext
* convert assistants to inherit from SceneAssistantBase

241
mojo.el
View file

@ -1,6 +1,6 @@
;;; mojo.el --- Interactive functions to aid the development of webOS apps
;; 2009-11-26 14:12:59
(defconst mojo-version "0.9.5")
;; 2009-12-01 08:29:25
(defconst mojo-version "0.9.6")
(require 'json)
@ -118,6 +118,57 @@ ideas. Send me a pull request on github if you hack on mojo.el.")
;;; Code:
(define-minor-mode mojo-mode
"Toggle Mojo mode.
With no argument, this command toggles the mode.
Non-null prefix argument turns on the mode.
Null prefix argument turns off the mode.
When Mojo mode is enabled various commands are enabled to
aid the development of Mojo applications.
Make sure you customize the variables
\\[mojo-project-directory], \\[mojo-sdk-directory] and
\\[mojo-build-directory].
Keybindings are:
* C-c a -- \\[mojo-switch-to-assistant]
* C-c i -- \\[mojo-switch-to-appinfo]
* C-c I -- \\[mojo-switch-to-index]
* C-c n -- \\[mojo-switch-to-next-view]
* C-c s -- \\[mojo-switch-to-sources]
* C-c S -- \\[mojo-switch-to-stylesheet]
* C-c v -- \\[mojo-switch-to-view]
* C-c SPC -- \\[mojo-switch-file-dwim]
* C-c C-e -- \\[mojo-emulate]
* C-c C-p -- \\[mojo-package]
* C-c C-r -- \\[mojo-package-install-and-inspect]
* C-c C-s -- \\[mojo-generate-scene]
* C-c C-t -- \\[mojo-toggle-target]
See the source code mojo.el or the README file for a list of
all of the interactive commands."
;; The initial value.
:init-value nil
;; The indicator for the mode line.
:lighter "-Mojo"
;; The minor mode bindings.
:keymap
'(("\C-ca" . mojo-switch-to-assistant)
("\C-ci" . mojo-switch-to-appinfo)
("\C-cI" . mojo-switch-to-index)
("\C-cn" . mojo-switch-to-next-view)
("\C-cs" . mojo-switch-to-sources)
("\C-cS" . mojo-switch-to-stylesheet)
("\C-cv" . mojo-switch-to-view)
("\C-c " . mojo-switch-file-dwim)
("\C-c\C-e" . mojo-emulate)
("\C-c\C-p" . mojo-package)
("\C-c\C-r" . mojo-package-install-and-inspect)
("\C-c\C-s" . mojo-generate-scene)
("\C-c\C-t" . mojo-toggle-target))
:group 'mojo)
(defcustom mojo-sdk-directory
(case system-type
@ -295,19 +346,28 @@ Sets `*mojo-target*' to \"tcp\"."
(setq *mojo-target* "tcp"))
;;* interactive
(defun mojo-toggle-target ()
"Automatically change the target device from 'usb' to 'tcp' and
vice versa."
(interactive)
(if (string= "usb" *mojo-target*)
(mojo-target-emulator)
(mojo-target-device)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Some support functions that grok the basics of a Mojo project. ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun drop-last-path-component (path)
(defun mojo-drop-last-path-component (path)
"Get the head of a path by dropping the last component."
(if (< (length path) 2)
path
(substring path 0 (- (length path)
(length (last-path-component path))
(length (mojo-last-path-component path))
1)))) ;; subtract one more for the trailing slash
(defun last-path-component (path)
(defun mojo-last-path-component (path)
"Get the tail of a path, i.e. the last component."
(if (< (length path) 2)
path
@ -321,20 +381,20 @@ Sets `*mojo-target*' to \"tcp\"."
(defun mojo-root ()
"Find a Mojo project's root directory starting with `DEFAULT-DIRECTORY'."
(let ((last-component (last-path-component default-directory))
(let ((last-component (mojo-last-path-component default-directory))
(dir-prefix default-directory))
;; remove last path element until we find appinfo.json
(while (and (not (file-exists-p (concat dir-prefix "/appinfo.json")))
(not (< (length dir-prefix) 2)))
(setq last-component (last-path-component dir-prefix))
(setq dir-prefix (drop-last-path-component dir-prefix)))
(setq last-component (mojo-last-path-component dir-prefix))
(setq dir-prefix (mojo-drop-last-path-component dir-prefix)))
;; If no Mojo root found, ask for a directory.
(if (< (length dir-prefix) 2)
(setq dir-prefix (mojo-read-root)))
;; Invalidate cached values when changing projects.
(if (or (blank *mojo-last-root*)
(if (or (mojo-blank *mojo-last-root*)
(not (string= dir-prefix *mojo-last-root*)))
(progn
(setq *mojo-last-root* dir-prefix)
@ -343,7 +403,14 @@ Sets `*mojo-target*' to \"tcp\"."
dir-prefix))
(defun read-json-file (filename)
;; foolproof?
(defun mojo-project-p ()
(and (file-exists-p (concat (mojo-root) "/appinfo.json"))
(file-exists-p (concat (mojo-root) "/sources.json"))
(file-exists-p (concat (mojo-root) "/app"))
(file-exists-p (concat (mojo-root) "/index.html"))))
(defun mojo-read-json-file (filename)
"Parse the JSON in FILENAME and return the result."
(save-excursion
(let ((origbuffer (current-buffer))
@ -355,13 +422,27 @@ Sets `*mojo-target*' to \"tcp\"."
(defun mojo-app-version ()
"Parse the project version from the appinfo.json file in `MOJO-ROOT'."
(let ((appinfo (read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'version appinfo))))
(when (mojo-project-p)
(let ((appinfo (mojo-read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'version appinfo)))))
(defun mojo-app-id ()
"Parse the project id from the appinfo.json file in `MOJO-ROOT'."
(let ((appinfo (read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'id appinfo))))
(when (mojo-project-p)
(let ((appinfo (mojo-read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'id appinfo)))))
(defun mojo-app-title ()
"Parse the project title from appinfo.json."
(when (mojo-project-p)
(let ((appinfo (mojo-read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'title appinfo)))))
(defun mojo-informal-app-id ()
"Parse the project title from appinfo.json and remove all non alphanumeric
characters."
(let ((title (downcase (mojo-app-title))))
(replace-regexp-in-string "[^a-z0-9]" "" title)))
(defun mojo-package-filename ()
"Get the package filename for the specified application."
@ -383,7 +464,7 @@ Sets `*mojo-target*' to \"tcp\"."
(let ((buffer (find-file-noselect *mojo-app-cache-filename*))
(apps (mojo-fetch-app-list)))
(set-buffer buffer)
(insert (string-join "\n" apps))
(insert (mojo-string-join "\n" apps))
(basic-save-buffer)
(kill-buffer buffer))))
*mojo-app-cache-filename*)
@ -405,11 +486,11 @@ Sets `*mojo-target*' to \"tcp\"."
"List of the most recently used package filenames.")
;; this is from rails-lib.el in the emacs-rails package
(defun string-join (separator strings)
(defun mojo-string-join (separator strings)
"Join all STRINGS using SEPARATOR."
(mapconcat 'identity strings separator))
(defun blank (thing)
(defun mojo-blank (thing)
"Return T if THING is nil or an empty string, otherwise nil."
(or (null thing)
(and (stringp thing)
@ -429,7 +510,7 @@ The app id is stored in *mojo-package-filename* unless it was blank."
(mojo-package-filename)))
(package (read-file-name (format "Package file (default: %s): " default)
(concat mojo-build-directory "/") default t)))
(setq *mojo-package-filename* (last-path-component package))
(setq *mojo-package-filename* (mojo-last-path-component package))
(expand-file-name package)))
(defun mojo-read-app-id (&optional prompt)
@ -447,7 +528,7 @@ The app id is stored in *mojo-app-id* unless it was blank."
nil
'*mojo-app-history*
default)))
(when (blank app-id)
(when (mojo-blank app-id)
(setq app-id (mojo-app-id)))
(setq *mojo-app-id* app-id)
app-id))
@ -499,6 +580,124 @@ If the cache file does not exist then it is considered stale."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; switch to files easily ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar *mojo-switch-suffixes*
'(("-assistant.js" . mojo-switch-to-view)
("-scene.html" . mojo-switch-to-assistant)
(".html" . mojo-switch-to-next-view)
("" . mojo-switch-to-appinfo)))
;;* interactive
(defun mojo-switch-to-appinfo ()
(interactive)
(find-file (concat (mojo-root) "/appinfo.json")))
;;* interactive
(defun mojo-switch-to-index ()
(interactive)
(find-file (concat (mojo-root) "/index.html")))
;;* interactive
(defun mojo-switch-to-sources ()
(interactive)
(find-file (concat (mojo-root) "/sources.json")))
;;* interactive
(defun mojo-switch-to-stylesheet ()
(interactive)
(let* ((stylesheet-dir (concat (mojo-root) "/stylesheets"))
(path (concat stylesheet-dir "/"
(mojo-informal-app-id) ".css")))
(when (not (file-exists-p path))
(setq path (car (mojo-filter-paths (directory-files stylesheet-dir t)))))
(find-file path)))
(defun mojo-scene-name-from-assistant ()
(let ((path (buffer-file-name)))
(substring (mojo-last-path-component path) 0 (- 0 (length "-assistant.js")))))
(defun mojo-scene-name-from-view ()
(mojo-last-path-component (mojo-drop-last-path-component (buffer-file-name))))
;;* interactive
(defun mojo-switch-file-dwim ()
"Determine if the current buffer is visiting a file with known
relationships. Try to find the 'best' choice and switch to it.
This does what I (sjs) mean by default, so change
*mojo-switch-suffixes* if you want different behaviour."
(interactive)
(let* ((path (buffer-file-name))
(suffixes (copy-list *mojo-switch-suffixes*))
(switch-function
(catch 'break
(dolist (pair suffixes nil)
(let ((suffix (car pair))
(function (cdr pair)))
(when (string= suffix (substring path (- 0 (length suffix))))
(throw 'break function)))))))
(when switch-function
(call-interactively switch-function))))
;;* interactive
(defun mojo-switch-to-view ()
(interactive)
(when (mojo-project-p)
(let ((scene-name (mojo-scene-name-from-assistant)))
(find-file (concat (mojo-root)
"/app/views/" scene-name "/"
scene-name "-scene.html")))))
(defun mojo-ignored-path (path)
(let ((filename (mojo-last-path-component path)))
(or (string= (substring filename 0 1) ".")
(and (string= (substring filename 0 1) "#")
(string= (substring filename -1) "#")))))
(defun mojo-filter-paths (all-paths)
(let ((wanted-paths (list)))
(dolist (path all-paths wanted-paths)
(unless (mojo-ignored-path path)
(setq wanted-paths (cons path wanted-paths))))
(reverse wanted-paths)))
(defun mojo-index (elem list)
(catch 'break
(let ((index 0))
(dolist (path list index)
(incf index)
(when (string= path elem)
(throw 'break index))))))
;;* interactive
(defun mojo-switch-to-next-view ()
(interactive)
(when (mojo-project-p)
(let* ((scene-name (mojo-scene-name-from-view))
(view-dir (concat (mojo-root) "/app/views/" scene-name))
(view-files (mojo-filter-paths (directory-files view-dir t)))
(mojo-filter-paths (directory-files (concat (mojo-root) "/app/views/" (mojo-scene-name-from-view)) t))
(index (mojo-index (buffer-file-name) view-files))
(filename (nth (mod index (length view-files)) view-files)))
(find-file filename))))
;;* interactive
(defun mojo-switch-to-assistant ()
(interactive)
(let ((scene-name (mojo-scene-name-from-view)))
(when (and (mojo-project-p)
scene-name)
(find-file (concat (mojo-root)
"/app/assistants/" scene-name "-assistant.js")))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;* lowlevel luna
(defun mojo-luna-send (url data)
"Send something through luna.
@ -540,7 +739,7 @@ CMD is the name of the command (without path or extension) to execute.
ARGS is a list of all arguments to the command.
These arguments are NOT shell quoted."
(let ((cmd (mojo-path-to-cmd cmd))
(args (string-join " " args)))
(args (mojo-string-join " " args)))
(if mojo-debug (message "running %s with args %s " cmd args))
(shell-command (concat cmd " " args))))
@ -566,7 +765,7 @@ ARGS is a list of all arguments to the command.
These arguments are NOT shell quoted."
(let ((cmd (mojo-path-to-cmd cmd))
(args (concat "-d " (or target *mojo-target*) " "
(string-join " " args))))
(mojo-string-join " " args))))
(if mojo-debug (message "running %s with args %s " cmd args))
(shell-command-to-string (concat cmd " " args))))

View file

@ -1,3 +1,54 @@
(define-minor-mode mojo-mode
"Toggle Mojo mode.
With no argument, this command toggles the mode.
Non-null prefix argument turns on the mode.
Null prefix argument turns off the mode.
When Mojo mode is enabled various commands are enabled to
aid the development of Mojo applications.
Make sure you customize the variables
\\[mojo-project-directory], \\[mojo-sdk-directory] and
\\[mojo-build-directory].
Keybindings are:
* C-c a -- \\[mojo-switch-to-assistant]
* C-c i -- \\[mojo-switch-to-appinfo]
* C-c I -- \\[mojo-switch-to-index]
* C-c n -- \\[mojo-switch-to-next-view]
* C-c s -- \\[mojo-switch-to-sources]
* C-c S -- \\[mojo-switch-to-stylesheet]
* C-c v -- \\[mojo-switch-to-view]
* C-c SPC -- \\[mojo-switch-file-dwim]
* C-c C-e -- \\[mojo-emulate]
* C-c C-p -- \\[mojo-package]
* C-c C-r -- \\[mojo-package-install-and-inspect]
* C-c C-s -- \\[mojo-generate-scene]
* C-c C-t -- \\[mojo-toggle-target]
See the source code mojo.el or the README file for a list of
all of the interactive commands."
;; The initial value.
:init-value nil
;; The indicator for the mode line.
:lighter "-Mojo"
;; The minor mode bindings.
:keymap
'(("\C-ca" . mojo-switch-to-assistant)
("\C-ci" . mojo-switch-to-appinfo)
("\C-cI" . mojo-switch-to-index)
("\C-cn" . mojo-switch-to-next-view)
("\C-cs" . mojo-switch-to-sources)
("\C-cS" . mojo-switch-to-stylesheet)
("\C-cv" . mojo-switch-to-view)
("\C-c " . mojo-switch-file-dwim)
("\C-c\C-e" . mojo-emulate)
("\C-c\C-p" . mojo-package)
("\C-c\C-r" . mojo-package-install-and-inspect)
("\C-c\C-s" . mojo-generate-scene)
("\C-c\C-t" . mojo-toggle-target))
:group 'mojo)
(defcustom mojo-sdk-directory
(case system-type
@ -175,19 +226,28 @@ Sets `*mojo-target*' to \"tcp\"."
(setq *mojo-target* "tcp"))
;;* interactive
(defun mojo-toggle-target ()
"Automatically change the target device from 'usb' to 'tcp' and
vice versa."
(interactive)
(if (string= "usb" *mojo-target*)
(mojo-target-emulator)
(mojo-target-device)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Some support functions that grok the basics of a Mojo project. ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun drop-last-path-component (path)
(defun mojo-drop-last-path-component (path)
"Get the head of a path by dropping the last component."
(if (< (length path) 2)
path
(substring path 0 (- (length path)
(length (last-path-component path))
(length (mojo-last-path-component path))
1)))) ;; subtract one more for the trailing slash
(defun last-path-component (path)
(defun mojo-last-path-component (path)
"Get the tail of a path, i.e. the last component."
(if (< (length path) 2)
path
@ -201,20 +261,20 @@ Sets `*mojo-target*' to \"tcp\"."
(defun mojo-root ()
"Find a Mojo project's root directory starting with `DEFAULT-DIRECTORY'."
(let ((last-component (last-path-component default-directory))
(let ((last-component (mojo-last-path-component default-directory))
(dir-prefix default-directory))
;; remove last path element until we find appinfo.json
(while (and (not (file-exists-p (concat dir-prefix "/appinfo.json")))
(not (< (length dir-prefix) 2)))
(setq last-component (last-path-component dir-prefix))
(setq dir-prefix (drop-last-path-component dir-prefix)))
(setq last-component (mojo-last-path-component dir-prefix))
(setq dir-prefix (mojo-drop-last-path-component dir-prefix)))
;; If no Mojo root found, ask for a directory.
(if (< (length dir-prefix) 2)
(setq dir-prefix (mojo-read-root)))
;; Invalidate cached values when changing projects.
(if (or (blank *mojo-last-root*)
(if (or (mojo-blank *mojo-last-root*)
(not (string= dir-prefix *mojo-last-root*)))
(progn
(setq *mojo-last-root* dir-prefix)
@ -223,7 +283,14 @@ Sets `*mojo-target*' to \"tcp\"."
dir-prefix))
(defun read-json-file (filename)
;; foolproof?
(defun mojo-project-p ()
(and (file-exists-p (concat (mojo-root) "/appinfo.json"))
(file-exists-p (concat (mojo-root) "/sources.json"))
(file-exists-p (concat (mojo-root) "/app"))
(file-exists-p (concat (mojo-root) "/index.html"))))
(defun mojo-read-json-file (filename)
"Parse the JSON in FILENAME and return the result."
(save-excursion
(let ((origbuffer (current-buffer))
@ -235,13 +302,27 @@ Sets `*mojo-target*' to \"tcp\"."
(defun mojo-app-version ()
"Parse the project version from the appinfo.json file in `MOJO-ROOT'."
(let ((appinfo (read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'version appinfo))))
(when (mojo-project-p)
(let ((appinfo (mojo-read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'version appinfo)))))
(defun mojo-app-id ()
"Parse the project id from the appinfo.json file in `MOJO-ROOT'."
(let ((appinfo (read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'id appinfo))))
(when (mojo-project-p)
(let ((appinfo (mojo-read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'id appinfo)))))
(defun mojo-app-title ()
"Parse the project title from appinfo.json."
(when (mojo-project-p)
(let ((appinfo (mojo-read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'title appinfo)))))
(defun mojo-informal-app-id ()
"Parse the project title from appinfo.json and remove all non alphanumeric
characters."
(let ((title (downcase (mojo-app-title))))
(replace-regexp-in-string "[^a-z0-9]" "" title)))
(defun mojo-package-filename ()
"Get the package filename for the specified application."
@ -263,7 +344,7 @@ Sets `*mojo-target*' to \"tcp\"."
(let ((buffer (find-file-noselect *mojo-app-cache-filename*))
(apps (mojo-fetch-app-list)))
(set-buffer buffer)
(insert (string-join "\n" apps))
(insert (mojo-string-join "\n" apps))
(basic-save-buffer)
(kill-buffer buffer))))
*mojo-app-cache-filename*)
@ -285,11 +366,11 @@ Sets `*mojo-target*' to \"tcp\"."
"List of the most recently used package filenames.")
;; this is from rails-lib.el in the emacs-rails package
(defun string-join (separator strings)
(defun mojo-string-join (separator strings)
"Join all STRINGS using SEPARATOR."
(mapconcat 'identity strings separator))
(defun blank (thing)
(defun mojo-blank (thing)
"Return T if THING is nil or an empty string, otherwise nil."
(or (null thing)
(and (stringp thing)
@ -309,7 +390,7 @@ The app id is stored in *mojo-package-filename* unless it was blank."
(mojo-package-filename)))
(package (read-file-name (format "Package file (default: %s): " default)
(concat mojo-build-directory "/") default t)))
(setq *mojo-package-filename* (last-path-component package))
(setq *mojo-package-filename* (mojo-last-path-component package))
(expand-file-name package)))
(defun mojo-read-app-id (&optional prompt)
@ -327,7 +408,7 @@ The app id is stored in *mojo-app-id* unless it was blank."
nil
'*mojo-app-history*
default)))
(when (blank app-id)
(when (mojo-blank app-id)
(setq app-id (mojo-app-id)))
(setq *mojo-app-id* app-id)
app-id))
@ -379,6 +460,124 @@ If the cache file does not exist then it is considered stale."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; switch to files easily ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar *mojo-switch-suffixes*
'(("-assistant.js" . mojo-switch-to-view)
("-scene.html" . mojo-switch-to-assistant)
(".html" . mojo-switch-to-next-view)
("" . mojo-switch-to-appinfo)))
;;* interactive
(defun mojo-switch-to-appinfo ()
(interactive)
(find-file (concat (mojo-root) "/appinfo.json")))
;;* interactive
(defun mojo-switch-to-index ()
(interactive)
(find-file (concat (mojo-root) "/index.html")))
;;* interactive
(defun mojo-switch-to-sources ()
(interactive)
(find-file (concat (mojo-root) "/sources.json")))
;;* interactive
(defun mojo-switch-to-stylesheet ()
(interactive)
(let* ((stylesheet-dir (concat (mojo-root) "/stylesheets"))
(path (concat stylesheet-dir "/"
(mojo-informal-app-id) ".css")))
(when (not (file-exists-p path))
(setq path (car (mojo-filter-paths (directory-files stylesheet-dir t)))))
(find-file path)))
(defun mojo-scene-name-from-assistant ()
(let ((path (buffer-file-name)))
(substring (mojo-last-path-component path) 0 (- 0 (length "-assistant.js")))))
(defun mojo-scene-name-from-view ()
(mojo-last-path-component (mojo-drop-last-path-component (buffer-file-name))))
;;* interactive
(defun mojo-switch-file-dwim ()
"Determine if the current buffer is visiting a file with known
relationships. Try to find the 'best' choice and switch to it.
This does what I (sjs) mean by default, so change
*mojo-switch-suffixes* if you want different behaviour."
(interactive)
(let* ((path (buffer-file-name))
(suffixes (copy-list *mojo-switch-suffixes*))
(switch-function
(catch 'break
(dolist (pair suffixes nil)
(let ((suffix (car pair))
(function (cdr pair)))
(when (string= suffix (substring path (- 0 (length suffix))))
(throw 'break function)))))))
(when switch-function
(call-interactively switch-function))))
;;* interactive
(defun mojo-switch-to-view ()
(interactive)
(when (mojo-project-p)
(let ((scene-name (mojo-scene-name-from-assistant)))
(find-file (concat (mojo-root)
"/app/views/" scene-name "/"
scene-name "-scene.html")))))
(defun mojo-ignored-path (path)
(let ((filename (mojo-last-path-component path)))
(or (string= (substring filename 0 1) ".")
(and (string= (substring filename 0 1) "#")
(string= (substring filename -1) "#")))))
(defun mojo-filter-paths (all-paths)
(let ((wanted-paths (list)))
(dolist (path all-paths wanted-paths)
(unless (mojo-ignored-path path)
(setq wanted-paths (cons path wanted-paths))))
(reverse wanted-paths)))
(defun mojo-index (elem list)
(catch 'break
(let ((index 0))
(dolist (path list index)
(incf index)
(when (string= path elem)
(throw 'break index))))))
;;* interactive
(defun mojo-switch-to-next-view ()
(interactive)
(when (mojo-project-p)
(let* ((scene-name (mojo-scene-name-from-view))
(view-dir (concat (mojo-root) "/app/views/" scene-name))
(view-files (mojo-filter-paths (directory-files view-dir t)))
(mojo-filter-paths (directory-files (concat (mojo-root) "/app/views/" (mojo-scene-name-from-view)) t))
(index (mojo-index (buffer-file-name) view-files))
(filename (nth (mod index (length view-files)) view-files)))
(find-file filename))))
;;* interactive
(defun mojo-switch-to-assistant ()
(interactive)
(let ((scene-name (mojo-scene-name-from-view)))
(when (and (mojo-project-p)
scene-name)
(find-file (concat (mojo-root)
"/app/assistants/" scene-name "-assistant.js")))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;* lowlevel luna
(defun mojo-luna-send (url data)
"Send something through luna.
@ -420,7 +619,7 @@ CMD is the name of the command (without path or extension) to execute.
ARGS is a list of all arguments to the command.
These arguments are NOT shell quoted."
(let ((cmd (mojo-path-to-cmd cmd))
(args (string-join " " args)))
(args (mojo-string-join " " args)))
(if mojo-debug (message "running %s with args %s " cmd args))
(shell-command (concat cmd " " args))))
@ -446,7 +645,7 @@ ARGS is a list of all arguments to the command.
These arguments are NOT shell quoted."
(let ((cmd (mojo-path-to-cmd cmd))
(args (concat "-d " (or target *mojo-target*) " "
(string-join " " args))))
(mojo-string-join " " args))))
(if mojo-debug (message "running %s with args %s " cmd args))
(shell-command-to-string (concat cmd " " args))))

View file

@ -2,6 +2,6 @@
"title": "mojo.el",
"filename": "../mojo.el",
"basename": "mojo.el",
"version": "0.9.5",
"version": "0.9.6",
"template": "template.el"
}