[CHANGED] mojo.el to version 0.9.6.

This commit is contained in:
Sami Samhuri 2009-12-03 09:53:43 -08:00
parent 24fcfb3dac
commit 1df8d20553

View file

@ -1,6 +1,6 @@
;;; ../mojo.el --- Interactive functions to aid the development of webOS apps ;;; mojo.el --- Interactive functions to aid the development of webOS apps
;; 2009-11-24 12:03:42 ;; 2009-12-01 08:29:25
(defconst mojo-version "0.9.4") (defconst mojo-version "0.9.6")
(require 'json) (require 'json)
@ -11,7 +11,7 @@
;; Sami Samhuri <sami.samhuri@gmail.com> ;; Sami Samhuri <sami.samhuri@gmail.com>
;; ;;
;; Latest version is available on github: ;; Latest version is available on github:
;; http://github.com/samsonjs/config/blob/master/emacs.d/mojo.el ;; http://github.com/samsonjs/mojo.el
;; ;;
;; With sufficient interest mojo.el will get its own repo. ;; With sufficient interest mojo.el will get its own repo.
@ -118,6 +118,57 @@ ideas. Send me a pull request on github if you hack on mojo.el.")
;;; Code: ;;; 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 (defcustom mojo-sdk-directory
(case system-type (case system-type
@ -295,19 +346,28 @@ Sets `*mojo-target*' to \"tcp\"."
(setq *mojo-target* "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. ;; ;; 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." "Get the head of a path by dropping the last component."
(if (< (length path) 2) (if (< (length path) 2)
path path
(substring path 0 (- (length 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 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." "Get the tail of a path, i.e. the last component."
(if (< (length path) 2) (if (< (length path) 2)
path path
@ -321,20 +381,20 @@ Sets `*mojo-target*' to \"tcp\"."
(defun mojo-root () (defun mojo-root ()
"Find a Mojo project's root directory starting with `DEFAULT-DIRECTORY'." "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)) (dir-prefix default-directory))
;; remove last path element until we find appinfo.json ;; remove last path element until we find appinfo.json
(while (and (not (file-exists-p (concat dir-prefix "/appinfo.json"))) (while (and (not (file-exists-p (concat dir-prefix "/appinfo.json")))
(not (< (length dir-prefix) 2))) (not (< (length dir-prefix) 2)))
(setq last-component (last-path-component dir-prefix)) (setq last-component (mojo-last-path-component dir-prefix))
(setq dir-prefix (drop-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 no Mojo root found, ask for a directory.
(if (< (length dir-prefix) 2) (if (< (length dir-prefix) 2)
(setq dir-prefix (mojo-read-root))) (setq dir-prefix (mojo-read-root)))
;; Invalidate cached values when changing projects. ;; 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*))) (not (string= dir-prefix *mojo-last-root*)))
(progn (progn
(setq *mojo-last-root* dir-prefix) (setq *mojo-last-root* dir-prefix)
@ -343,7 +403,14 @@ Sets `*mojo-target*' to \"tcp\"."
dir-prefix)) 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." "Parse the JSON in FILENAME and return the result."
(save-excursion (save-excursion
(let ((origbuffer (current-buffer)) (let ((origbuffer (current-buffer))
@ -355,13 +422,27 @@ Sets `*mojo-target*' to \"tcp\"."
(defun mojo-app-version () (defun mojo-app-version ()
"Parse the project version from the appinfo.json file in `MOJO-ROOT'." "Parse the project version from the appinfo.json file in `MOJO-ROOT'."
(let ((appinfo (read-json-file (concat (mojo-root) "/appinfo.json")))) (when (mojo-project-p)
(cdr (assoc 'version appinfo)))) (let ((appinfo (mojo-read-json-file (concat (mojo-root) "/appinfo.json"))))
(cdr (assoc 'version appinfo)))))
(defun mojo-app-id () (defun mojo-app-id ()
"Parse the project id from the appinfo.json file in `MOJO-ROOT'." "Parse the project id from the appinfo.json file in `MOJO-ROOT'."
(let ((appinfo (read-json-file (concat (mojo-root) "/appinfo.json")))) (when (mojo-project-p)
(cdr (assoc 'id appinfo)))) (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 () (defun mojo-package-filename ()
"Get the package filename for the specified application." "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*)) (let ((buffer (find-file-noselect *mojo-app-cache-filename*))
(apps (mojo-fetch-app-list))) (apps (mojo-fetch-app-list)))
(set-buffer buffer) (set-buffer buffer)
(insert (string-join "\n" apps)) (insert (mojo-string-join "\n" apps))
(basic-save-buffer) (basic-save-buffer)
(kill-buffer buffer)))) (kill-buffer buffer))))
*mojo-app-cache-filename*) *mojo-app-cache-filename*)
@ -405,11 +486,11 @@ Sets `*mojo-target*' to \"tcp\"."
"List of the most recently used package filenames.") "List of the most recently used package filenames.")
;; this is from rails-lib.el in the emacs-rails package ;; 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." "Join all STRINGS using SEPARATOR."
(mapconcat 'identity strings separator)) (mapconcat 'identity strings separator))
(defun blank (thing) (defun mojo-blank (thing)
"Return T if THING is nil or an empty string, otherwise nil." "Return T if THING is nil or an empty string, otherwise nil."
(or (null thing) (or (null thing)
(and (stringp thing) (and (stringp thing)
@ -429,7 +510,7 @@ The app id is stored in *mojo-package-filename* unless it was blank."
(mojo-package-filename))) (mojo-package-filename)))
(package (read-file-name (format "Package file (default: %s): " default) (package (read-file-name (format "Package file (default: %s): " default)
(concat mojo-build-directory "/") default t))) (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))) (expand-file-name package)))
(defun mojo-read-app-id (&optional prompt) (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 nil
'*mojo-app-history* '*mojo-app-history*
default))) default)))
(when (blank app-id) (when (mojo-blank app-id)
(setq app-id (mojo-app-id))) (setq app-id (mojo-app-id)))
(setq *mojo-app-id* app-id) (setq *mojo-app-id* 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 ;;* lowlevel luna
(defun mojo-luna-send (url data) (defun mojo-luna-send (url data)
"Send something through luna. "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. ARGS is a list of all arguments to the command.
These arguments are NOT shell quoted." These arguments are NOT shell quoted."
(let ((cmd (mojo-path-to-cmd cmd)) (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)) (if mojo-debug (message "running %s with args %s " cmd args))
(shell-command (concat 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." These arguments are NOT shell quoted."
(let ((cmd (mojo-path-to-cmd cmd)) (let ((cmd (mojo-path-to-cmd cmd))
(args (concat "-d " (or target *mojo-target*) " " (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)) (if mojo-debug (message "running %s with args %s " cmd args))
(shell-command-to-string (concat cmd " " args)))) (shell-command-to-string (concat cmd " " args))))