(defvar dojo-js-tree-activated nil "Flag indicating that dojo-tree-mode is activated for that buffer.") (make-variable-buffer-local 'dojo-js-tree-activated) (defvar DOJO-TREE-MODE-CLASS) (defvar DOJO-TREE-MODE-CSS) (defvar dojo-js-tree-mode nil "") (defvar dojo-js-tree-key-to-data nil "Map from numeric keys to corresponding symbols. Used for easily identifying things shown in the *Tree* buffer in commands.") (defun dojo-js-tree-show-class-members () (interactive) (let* ((tree-buffer (dojo-core-window-show-tree-buffer)) (resource (dojo-core-util-get-current-resource)) (api-class (if resource (dojo-js-api-get-class-by-resource-id (dojo-resource-id resource)) nil))) (setq dojo-js-tree-key-to-data (make-hash-table :test 'equal)) (setq dojo-js-tree-mode 'DOJO-TREE-MODE-CLASS) (with-current-buffer tree-buffer (erase-buffer) (dojo-js-tree-insert-class-header api-class) (dojo-js-tree-insert-class-members api-class) ))) (defun dojo-js-tree-insert-class-header (api-class) (let* ((project (dojo-class-project api-class)) (path (dojo-class-path api-class)) (path-tokens (split-string path "/"))) (insert project) (newline) (let* ((curr-length 0) (curr-index 0) (line-start t) (indentation 2) (line 0)) (dolist (path-token path-tokens) (let* ((curr-path-token (if (< curr-index (1- (length path-tokens))) (concat path-token "/") path-token))) (if (and (not line-start) (>= (+ curr-length 1 (length curr-path-token)) 50)) ; See also dojo-core-window, initialize-side-windows (progn (newline) (incf indentation) (incf line) (setq line-start t))) (if line-start (progn (setq curr-length indentation) (insert-char ?\s indentation) (setq line-start nil) (incf line) (if (> line 0) (setq curr-path-token (concat "/" curr-path-token))))) (setq curr-length (+ curr-length (length curr-path-token))) (insert curr-path-token) (incf curr-index)))))) (defun dojo-js-tree-insert-class-members (api-class) (newline) (newline) (let* ((this-symbol (dojo-class-this-symbol api-class)) (this-name-to-symbol (dojo-symbol-get-object-members this-symbol)) (static-symbol (dojo-class-static-symbol api-class)) (static-name-to-symbol (dojo-symbol-get-object-members static-symbol)) (member-count (+ (hash-table-count this-name-to-symbol) (hash-table-count static-name-to-symbol))) (member-count-length (if (> member-count 0) (ceiling (log10 member-count)) 0)) (curr-number 0) (api-resource-id (dojo-class-resource-id api-class)) (instance-members ()) (static-members ())) (maphash (lambda (name symbol) (push (list name symbol) instance-members)) this-name-to-symbol) (setq instance-members (sort instance-members (lambda (member-one member-two) (string< (nth 0 member-one) (nth 0 member-two))))) (maphash (lambda (name symbol) (push (list name symbol) static-members)) static-name-to-symbol) (setq static-members (sort static-members (lambda (member-one member-two) (string< (nth 0 member-one) (nth 0 member-two))))) (dolist (member instance-members) (let* ((name (nth 0 member)) (symbol (nth 1 member)) (number-string (number-to-string curr-number)) (symbol-id (dojo-symbol-id symbol))) (insert-char ?\s (- member-count-length (length number-string))) (insert (concat number-string " " name)) (newline) (puthash curr-number (list symbol-id api-resource-id) dojo-js-tree-key-to-data) (incf curr-number))) (dolist (member static-members) (let* ((name (nth 0 member)) (symbol (nth 1 member)) (number-string (number-to-string curr-number)) (symbol-id (dojo-symbol-id symbol))) (insert-char ?\s (- member-count-length (length number-string))) (insert (concat number-string " " name)) (newline) (puthash curr-number (list symbol-id api-resource-id) dojo-js-tree-key-to-data) (incf curr-number))))) (defun dojo-js-tree-show-css () (interactive) (let* ((tree-buffer (dojo-core-window-show-tree-buffer)) (name-to-project (dojo-workspace-name-to-project dojo-current-workspace)) (projects (if name-to-project (hash-table-get-all-keys name-to-project) nil)) (project-to-css-list (make-hash-table :test 'equal)) (total-count 0)) (setq dojo-js-tree-key-to-data (make-hash-table :test 'equal)) (setq dojo-js-tree-mode 'DOJO-TREE-MODE-CSS) (if projects (with-current-buffer tree-buffer (erase-buffer) (setq project-names (sort projects 'string<)) (dolist (project-name project-names) (let* ((project (gethash project-name name-to-project)) (css-resources (dojo-project-css-resources project)) (css-list (dojo-js-tree-get-css-list css-resources))) (puthash project-name css-list project-to-css-list) (setq total-count (+ total-count (length css-list))))) (let* ((count-length (if (> total-count 0) (ceiling (log10 total-count)) 0)) (curr-number 0)) (maphash (lambda (project-name css-list) (if (> (length css-list) 0) (progn (insert project-name) (newline) (dolist (css-list-item css-list) (let* ((resource-id (nth 0 css-list-item)) (resource-name (nth 1 css-list-item)) (is-main-resource (nth 2 css-list-item)) (number-string (number-to-string curr-number))) (insert-char ?\s (- count-length (length number-string))) (insert (concat number-string " " resource-name)) (newline) (puthash curr-number css-list-item dojo-js-tree-key-to-data) (incf curr-number))) (newline)))) project-to-css-list)))))) (defun dojo-js-tree-get-css-list (css-resources) (let* ((css-list ()) (id-to-resource (dojo-workspace-id-to-resource dojo-current-workspace)) (main-resource-id (gethash DOJO-PROJECT-CSS-MAIN css-resources))) (maphash (lambda (resource-id-key resource-id-value) (let* ((resource (gethash resource-id-value id-to-resource)) (resource-path (if resource (dojo-resource-path resource) nil)) (project (if resource (dojo-resource-project resource) nil)) (is-main-resource (and (stringp resource-id-key) (string= resource-id-key DOJO-PROJECT-CSS-MAIN))) (resource-path (if resource (dojo-resource-path resource) nil)) (resource-name (if resource-path (get-last-token resource-path "/")))) (if (and resource-path resource-name ; Restrict to main resources for now, to make the list shorter is-main-resource ; Ignore entries for the main resource, which don't have DOJO-PROJECT-CSS-MAIN as key ; (background: main resources show up twice: Once with their id as key, and once ; with DOJO-PROJECT-CSS-MAIN as key --- but we only want to recognize ; them once, with key DOJO-PROJECT-CSS-MAIN) (not (and (not (null main-resource-id)) (= main-resource-id resource-id-value) (not is-main-resource)))) (push (list resource-id-value resource-name is-main-resource) css-list)))) css-resources) (setq css-list (sort css-list (lambda (list-one list-two) (string< (nth 1 list-one) (nth 1 list-two))))) css-list)) (define-derived-mode dojo-tree-mode fundamental-mode "Tree" "A major mode to be active in the *Tree* buffer." (let ((map (make-keymap))) ; (define-key map [remap save-buffer] 'dojo-js-symbols-save-symbol) (use-local-map map)) (setq dojo-js-tree-activated t)) (provide 'dojo-js-tree)