Skip to content

Commit

Permalink
Optimize and simplify haskell-ds-create-imenu-index with hashtable
Browse files Browse the repository at this point in the history
The function has implemented a poor man's hash table by manually
enlisting keys and then using `cl-case` on values. Just replace this
with a hashtable and thus simplify the code considerably. This makes
it faster as well because the `cl-case + setq` is O(n) whereas
`puthash` is O(1).

The output of the function was tested on Pandoc's
`Writers/Powerpoint/Output.hs` file of 2841 lines and comparing the
hashsum of the output before the changes and after. It didn't change.

The commit is also basically a backport of a similar change on
purescript-mode that has been forked form haskell-mode at some point:
purescript-emacs/purescript-mode#27
  • Loading branch information
Hi-Angel committed Nov 11, 2024
1 parent 7d4529a commit 89c6f2d
Showing 1 changed file with 14 additions and 41 deletions.
55 changes: 14 additions & 41 deletions haskell-decl-scan.el
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
(require 'haskell-mode)
(require 'syntax)
(require 'imenu)
(require 'subr-x)

(defgroup haskell-decl-scan nil
"Haskell declaration scanning (`imenu' support)."
Expand Down Expand Up @@ -537,11 +538,7 @@ datatypes) in a Haskell file for the `imenu' package."
;; These lists are nested using `(INDEX-TITLE . INDEX-ALIST)'.
(let* ((bird-literate (haskell-ds-bird-p))
(index-alist '())
(index-class-alist '()) ;; Classes
(index-var-alist '()) ;; Variables
(index-imp-alist '()) ;; Imports
(index-inst-alist '()) ;; Instances
(index-type-alist '()) ;; Datatypes
(imenu (make-hash-table :test 'equal))
;; The result we wish to return.
result)
(goto-char (point-min))
Expand All @@ -557,47 +554,23 @@ datatypes) in a Haskell file for the `imenu' package."
(posns (cdr name-posns))
(start-pos (car posns))
(type (cdr result)))
;; Place `(name . start-pos)' in the correct alist.
(cl-case type
(variable
(setq index-var-alist
(cl-acons name start-pos index-var-alist)))
(datatype
(setq index-type-alist
(cl-acons name start-pos index-type-alist)))
(class
(setq index-class-alist
(cl-acons name start-pos index-class-alist)))
(import
(setq index-imp-alist
(cl-acons name start-pos index-imp-alist)))
(instance
(setq index-inst-alist
(cl-acons name start-pos index-inst-alist)))))))
(puthash type
(cons (cons name start-pos) (gethash type imenu '()))
imenu))))
;; Now sort all the lists, label them, and place them in one list.
(when index-type-alist
(push (cons "Datatypes"
(sort index-type-alist 'haskell-ds-imenu-label-cmp))
index-alist))
(when index-inst-alist
(push (cons "Instances"
(sort index-inst-alist 'haskell-ds-imenu-label-cmp))
index-alist))
(when index-imp-alist
(push (cons "Imports"
(sort index-imp-alist 'haskell-ds-imenu-label-cmp))
index-alist))
(when index-class-alist
(push (cons "Classes"
(sort index-class-alist 'haskell-ds-imenu-label-cmp))
index-alist))
(when index-var-alist
(dolist (type '((datatype . "Datatypes") (instance . "Instances")
(import . "Imports") (class . "Classes")))
(when-let* ((curr-alist (gethash (car type) imenu)))
(push (cons (cdr type)
(sort curr-alist 'haskell-ds-imenu-label-cmp))
index-alist)))
(when-let* ((var-alist (gethash 'variable imenu)))
(if haskell-decl-scan-bindings-as-variables
(push (cons "Variables"
(sort index-var-alist 'haskell-ds-imenu-label-cmp))
(sort var-alist 'haskell-ds-imenu-label-cmp))
index-alist)
(setq index-alist (append index-alist
(sort index-var-alist 'haskell-ds-imenu-label-cmp)))))
(sort var-alist 'haskell-ds-imenu-label-cmp)))))
;; Return the alist.
index-alist))

Expand Down

0 comments on commit 89c6f2d

Please sign in to comment.