unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#61436: Emacs Freezing With Java Files
@ 2023-02-11 18:16 Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-02-12  0:24 ` Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-02-12  6:00 ` Eli Zaretskii
  0 siblings, 2 replies; 33+ messages in thread
From: Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-11 18:16 UTC (permalink / raw)
  To: 61436


[-- Attachment #1.1: Type: text/plain, Size: 1901 bytes --]

I have a few Java files that are about 500 lines of code and I can't move around in them much before Emacs freezes. I first thought it was java-lsp but it still happened after disabling and uninstalling it. I also uninstalled lsp-mode as well, but that didn't change anything.

I started doing CPU profiles of it and found that which-function-mode was taking up 67% of my CPU usage. While this is happening all I was doing was holding the down arrow until it froze about 350 lines in. Didn't press any other buttons.

So I disabled which-function-mode and moved around the buffer just fine! Though when trying to edit the file (just hit enter), it froze again. This time it seems like electric-indent-mode was taking up close to 50% of my CPU usage.

I disabled that and tried again and then it froze again with c-indent-line-or-region eating up 63% of my CPU when I use TAB.

While using debug-on-quit I get the below output. Any idea what's happening here and how it can be addressed? I do know though that if I launch emacs with the -Q argument, then there aren't any problems at all. I tried large files of other types and it only seems to happen with Java files. I attached screenshots of the CPU profiler outputs for each of the three scenarios. Attached is also the Java file as well as my init file.

I am using emacs version 28.2 on EndeavorOS, but reproduced the results using both emacs 29 and the master branch.

Debugger entered--Lisp error: (quit)
beginning-of-defun()
c-get-fallback-scan-pos(17794)
c-parse-state-get-strategy(17794 1)
c-parse-state-1()
c-parse-state()
c-guess-basic-syntax()
c-indent-line()
#f(compiled-function () (interactive nil) #<bytecode 0x180248dcca1cc57e>)()
c-indent-command(nil)
c-indent-line-or-region(nil nil)
funcall-interactively(c-indent-line-or-region nil nil)
call-interactively(c-indent-line-or-region nil nil) command-execute(c-indent-line-or-region)

[-- Attachment #1.2: Type: text/html, Size: 2972 bytes --]

[-- Attachment #2: emacs-freezing-cpu-profile-indent-mode-off.png --]
[-- Type: image/png, Size: 51786 bytes --]

[-- Attachment #3: emacs-freezing-cpu-profile.png --]
[-- Type: image/png, Size: 53977 bytes --]

[-- Attachment #4: emacs-freezing-cpu-profile-no-function-mode.png --]
[-- Type: image/png, Size: 103597 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: P1.java --]
[-- Type: text/x-java; name=P1.java, Size: 18142 bytes --]

public class P1 {
  /*
  This tests the Sym and SymTable classes. The tests have been broken up into
  five private helper methods for organizational purposes.
  */

  public static void main(String[] args) {
    testSym();
    testExceptions();
    testAddDecl();
    testLookup();
    testPrint();
  }

  /*
  Helper method to format errors properly which prints out to stderr
  */
  private static void error(String method, String msg) {
    System.err.println("ERROR: " + method + ": " + msg);
  }

  private static void testSym() {
    /*
      Testing our Sym methods using the different variable types (bool, int,
      string)
     */
    String[] typeList = {"bool", "int", "string"};
    for (int i = 0; i < typeList.length; i++) {
      Sym sym = new Sym(typeList[i]);
      String type = sym.getType();

      if (!type.equals(typeList[i])) {
        error("Sym.getType expecting ", type + ", but got " + typeList[i]);
      }
      type = sym.toString();
      if (!type.equals(typeList[i])) {
        error("Sym.toString expecting ", type + ", but got " + typeList[i]);
      }
    }
  }

  private static void testExceptions() {
    /*
    This is testing that the SymTable class will throw the EmptySymTable
    exception when expected as well as the ability to add and remove scope, the
    ability to add to our SymTable with one and multiple HashMaps with addDecl
    */
    SymTable symTable;

    // testing remove after calling the constructor
    try {
      symTable = new SymTable();
      symTable.removeScope();
      try {
        symTable.removeScope(); // Should throw an exception.
        error("SymTable.removeScope",
              "should throw an exception for an empty table");
      } catch (EmptySymTableException e) {
        // Expecting
      } catch (Exception e) {
        error("SymTable.removeScope", "wrong exception for an empty table");
      }
    } catch (EmptySymTableException e) {
      error("SymTable.removeScope",
            "EmptySymTableException thrown after calling SymTable constructor");
    } catch (Exception e) {
      error("SymTable.removeScope",
            e + " thrown after calling SymTable constructor");
    }

    // testing remove after adding/removing a map
    try {
      symTable = new SymTable();
      symTable.addScope();
      symTable.addScope();
      symTable.addScope();

      try {
        symTable.removeScope();
        symTable.removeScope();
        symTable.removeScope();
        symTable.removeScope(); // Should have zero maps now

        try {
          symTable.removeScope(); // Should throw an error.
          error("SymTable.removeScope",
                "should throw an exception for an empty table");
        } catch (EmptySymTableException e) {
          // Expecting
        } catch (Exception e) {
          error("SymTable.removeScope", "wrong exception for an empty table");
        }
      } catch (Exception e) {
        error("SymTable.removeScope",
              "unexpected exception for a non-empty table " + e);
      }
    } catch (Exception e) {
      error("SymTable.addScope", "unexpected exception " + e);
    }

    // Testing to see if addDecl throws an EmptySymTableException
    try {
      symTable = new SymTable();
      symTable.removeScope();

      try {
        symTable.addDecl("name", new Sym("type"));
        error("SymTable.addDecl",
              "should throw an EmptySymTableException for an empty SymTable");
      } catch (EmptySymTableException e) {
        // Expecting
      } catch (Exception e) {
        error("SymTable.addDecl", "wrong exception for an empty SymTable");
      }
    } catch (Exception e) {
      error("SymTable.removeScope",
            "unexpected exception thrown for a non-empty table " + e);
    }

    // Testing to see if addDecl throws an NullPointerException
    symTable = new SymTable();

    try {
      symTable.addDecl(null, new Sym("type"));
      error("SymTable.addDecl",
            "should throw an NullPointerException for 'addDecl(null, sym)'");
    } catch (NullPointerException e) {
      //  Expecting
    } catch (Exception e) {
      error("SymTable.addDecl", " wrong exception for 'addDecl(null, sym)'");
    }

    try {
      symTable.addDecl("name", null);
      error("SymTable.addDecl",
            "should throw an NullPointerException for 'addDecl(name, null)'");
    } catch (NullPointerException e) {
      // Expecting
    } catch (Exception e) {
      error("SymTable.addDecl", " wrong exception for 'addDecl(name, null)'");
    }

    try {
      symTable.addDecl(null, null);
      error("SymTable.addDecl",
            "should throw an NullPointerException for 'addDecl(null, null)'");
    } catch (NullPointerException e) {
      // Expecting
    } catch (Exception e) {
      error("SymTable.addDecl", " wrong exception for 'addDecl(null, null)'");
    }
  }
  private static void testAddDecl() {
    /*
    This is testing adding to our table with not only one, but multiple HashMap,
    as well as with and without unique names, and makes sure that duplicate
    names throw the DuplicateSymException
    */
    SymTable symTable;
    String name1 = "name1", name2 = "name2", name3 = "name3";
    Sym sym1 = new Sym("bool"), sym2 = new Sym("int");

    // Add into symTable with a single HashMap
    try {
      symTable = new SymTable();
      symTable.addDecl(name1, sym1);
      symTable.addDecl(name2, sym2);
      symTable.addDecl(name3, sym1);

      try {
        symTable.addDecl(name1, sym2);
        error("SymTable.addDecl", "did not throw exception for duplicate name");
      } catch (DuplicateSymException e) {
        // Expecting
      } catch (Exception e) {
        error("SymTable.addDecl", "wrong exception for duplicate name");
      }
    } catch (Exception e) {
      error("symTable.addDecl", "unexpected error with a single HashMap " + e);
    }

    // Add into symTable with multiple HashMap
    try {
      symTable = new SymTable();
      symTable.addDecl(name1, sym1);

      symTable.addScope();
      symTable.addDecl(name2, sym2);

      symTable.addScope();
      symTable.addDecl(name3, sym1);

      try {
        symTable.addDecl(name1, sym2);
      } catch (DuplicateSymException e) {
        error("SymTable.addDecl",
              "exception thrown when name added in another HashMap");
      }
      try {
        symTable.addDecl(name3, sym2);
        error(
            "SymTable.addDecl",
            "exception not thrown when duplicate name added with multiple HashMaps");
      } catch (DuplicateSymException e) {
        // Expecting
      } catch (Exception e) {
        error(
            "SymTable.addDecl",
            "wrong exception thrown when duplicate name added with multiple HashMaps");
      }
    } catch (Exception e) {
      error("SymTable.addDecl",
            "unexpected exception with multiple HashMaps " + e);
    }
  }

  private static void testLookup() {
    /*
    Tests both the local and global lookup methods where both would succeed and
    fail with one and multiple HashMap
     */
    Sym sym, intSym = new Sym("int");
    SymTable symTable = new SymTable();
    String name;

    //  wrap the method in a try-catch block so we can catch any exceptions
    //  thrown
    try {
      symTable = new SymTable();
      symTable.removeScope();

      // Testing local and global lookup with no map
      try {
        if (symTable.lookupLocal("xyz") != null) {
          error("symTable.lookupLocal('xyz')",
                "did not throw an exception for a Symtable with no maps");
        }
      } catch (Exception e) {
        // Expecting
      }
      try {
        if (symTable.lookupGlobal("xyz") != null) {
          error("symTable.lookupGlobal('xyz')",
                "did not throw an exception for a Symtable with no maps");
        }
      } catch (Exception e) {
        // Expecting
      }

      // Testing local and global lookup with a single map
      symTable = new SymTable();
      if (symTable.lookupLocal("xyz") != null) {
        error("symTable.lookupLocal('xyz')",
              "did not return null for a Symtable lookup of xyz");
      }
      if (symTable.lookupGlobal("xyz") != null) {
        error("symTable.lookupGlobal('xyz')",
              "did not return null for a Symtable lookup of xyz");
      }

      // Lookup for items that have been added to the table, and make sure
      // there isn't an unexpected success
      symTable.addDecl("xyz", intSym);
      if (symTable.lookupLocal("xyz") == null) {
        error("symTable.localLookup('xyz')",
              "failed for table with one item unexpectedly"); //???
      }
      if (symTable.lookupGlobal("xyz") == null) {
        error("symTable.localGlobal('xyz')",
              "failed for table with one item unexpectedly"); //???
      }
      if (symTable.lookupLocal("x") != null) {
        error("symTable.localLookup('x')",
              "succeeded for table with one item, when the item doesn't exist");
      }
      if (symTable.lookupGlobal("x") != null) {
        error("symTable.localGlobal('x')",
              "succeeded for table with one item, when the item doesn't exist");
      }

      // Testing local/global lookup with multiple maps
      symTable.addScope();
      symTable.addDecl("zyx", intSym);
      symTable.addScope();
      Sym doubleSym = new Sym("double");
      symTable.addDecl("abc", doubleSym);

      if (symTable.lookupLocal("xyz") != null) {
        error("symTable.lookupLocal('xyz')",
              "null not returned for value lookup of 'xyz' in third map");
      }
      if (symTable.lookupGlobal("xyz") != intSym) {
        error(
            "symTable.lookupGlobal('xyz')",
            "incorrect value returned for value lookup of 'xyz' in third map");
      }
      if (symTable.lookupLocal("zyx") != null) {
        error("symTable.lookupLocal('zyx')",
              "null not returned for value lookup of 'zyx' in second map");
      }
      if (symTable.lookupGlobal("zyx") != intSym) {
        error(
            "symTable.lookupGlobal('zyx')",
            "incorrect value returned for value lookup of 'zyx' in second map");
      }
      if (symTable.lookupLocal("abc") != doubleSym) {
        error("symTable.lookupLocal('abc')",
              "null not returned for value lookup of 'abc' in local map");
      }
      if (symTable.lookupGlobal("abc") != doubleSym) {
        error(
            "symTable.lookupGlobal('abc')",
            "incorrect value returned for value lookup of 'abc' in local map");
      }

      // testing local/global after removing a map
      symTable.removeScope();
      if (symTable.lookupLocal("abc") != null) {
        error(
            "symTable.lookupLocal('abc')",
            "null not returned for 'abc' lookup, after being removed from table");
      }
      if (symTable.lookupGlobal("abc") != null) {
        error(
            "symTable.lookupGlobal('abc')",
            "null not returned for 'abc' lookup, after being removed from table");
      }

      // Adding in multiple items, looking them up localy/globaly after adding
      // and again after all are added
      symTable = new SymTable();
      name = "x";
      sym = new Sym("float");

      for (int i = 0; i < 5; i++) {
        try {
          symTable.addDecl(name, sym);
        } catch (DuplicateSymException e) {
          error(
              "symTable.addDecl",
              "DuplicateSymException for table with one HashMap, but multiple entries");
        } catch (EmptySymTableException e) {
          error(
              "symTable.addDecl",
              "EmptySymTableException for table with one HashMap, but multiple entries");
        }
        if (symTable.lookupLocal(name) == null) {
          error("symTable.localLookup",
                "failure for table with one HashMap, but multiple entries");
        } else if (symTable.lookupLocal(name) != sym) {
          error(
              "symTable.localLookup",
              "wrong value returned for table with one HashMap, but multiple entries");
        }
        if (symTable.lookupGlobal(name) == null) {
          error("symTable.localGlobal",
                "failure for table with one HashMap, but multiple entries");
        } else if (symTable.lookupGlobal(name) != sym) {
          error(
              "symTable.localGlobal",
              "wrong value returned for table with one HashMap, but multiple entries");
        }
        name += "x";
      }

      // Lookup for items that have been added to the table
      name = "x";
      for (int i = 0; i < 5; i++) {
        if (symTable.lookupLocal(name) == null) {
          error("symTable.localLookup",
                "failure for table with one HashMap, but multiple entries"
                    + "lookup after adding all values");
        }
        if (symTable.lookupGlobal(name) == null) {
          error("symTable.localGlobal",
                "failure for table with one HashMap, but multiple entries"
                    + "lookup after adding all values");
        }
        name += "x";
      }

      /*
      Adding a second HashMap and taking the names from the first HashMap and
      putting them in the second one and making sure they can be added
      without errors being triggered.
       */
      symTable.addScope();
      name = "x";
      if (symTable.lookupGlobal(name) != sym) {
        error(
            "symTable.localGlobal",
            "bad value returned for name in non local HashMap of table with multiple HashMap");
      }
      for (int i = 0; i < 5; i++) {
        if (symTable.lookupLocal(name) != null) {
          error(
              "symTable.localLookup",
              "null not returned, when expected, for name in local HashMap of table with multiple HashMap");
        }
        if (symTable.lookupGlobal(name) != sym) {
          error(
              "symTable.localGlobal",
              "null returned, when unexpected, for name in non local HashMap of table with multiple HashMap");
        }
        name += "x";
      }

      // Adding names into the second HashMap that aren't in the first one and
      // making sure that they can be found
      name = "z";
      for (int i = 0; i < 5; i++) {
        sym = new Sym("float");
        try {
          symTable.addDecl(name, sym);
          if (symTable.lookupLocal(name) == null) {
            error("symTable.localLookup",
                  "failure for adding new name in second HashMap");
          } else if (symTable.lookupLocal(name) != sym) {
            error(
                "symTable.localLookup",
                "incorrect value returned for adding name to table with multiple HashMap");
          }
          if (symTable.lookupGlobal(name) == null) {
            error("symTable.localGlobal",
                  "failure for adding new name in second HashMap");
          } else if (symTable.lookupGlobal(name) != sym) {
            error(
                "symTable.localGlobal",
                "incorrect value returned for adding name to table with multiple HashMap");
          }

        } catch (DuplicateSymException e) {
          error(
              "symTable.addDecl",
              "DuplicateSymException for table with multiple HashMap, new name");
        } catch (EmptySymTableException e) {
          error(
              "symTable.addDecl",
              "EmptySymTableException for table with multiple HashMap, new name");
        }
        name += "z";
      }
      // Symtable with 10 HashMap and 10 names in each HashMap
      for (int i = 0; i < 10; i++) {
        Integer tableInt = Integer.valueOf(i);
        symTable.addScope();
        for (int j = 0; j < 10; j++) {
          Integer symInt = Integer.valueOf(j);
          name = tableInt.toString() + symInt.toString();
          sym = new Sym("int");
          try {
            symTable.addDecl(name, sym);
            if (symTable.lookupLocal(name) != sym) {
              error("symTable.localLookup",
                    "failure for table with many HashMap (10)");
            }
            if (symTable.lookupGlobal(name) != sym) {
              error("symTable.localGlobal",
                    "failure for table with many HashMap (10)");
            }
          } catch (DuplicateSymException e) {
            error("symTable.addDecl",
                  "DuplicateSymException for table with many HashMap (10)");
          } catch (EmptySymTableException e) {
            error("symTable.addDecl",
                  "EmptySymTableException for table with many HashMap (10)");
          }
        }
      }

      // Testing global lookup for a name from each HashMap
      for (int i = 0; i < 10; i++) {
        Integer tableInt = Integer.valueOf(i);
        name = tableInt.toString() + "1";
        if (symTable.lookupGlobal(name) == null) {
          error("symTable.globalLookup",
                "failure for table with many HashMap (10, after all added)");
        }
      }
    } catch (Exception e) {
      error("SymTable", "unexpected exception " + e +
                            " using addDecl/removeScope when testing lookup");
    }
  }

  private static void testPrint() {
    /*
    Tests the print function by calling it with no HashMap, a single HashMap,
    and multiple HashMap.
     */
    SymTable symTable = new SymTable();
    try {
      symTable.print();
      try {
        symTable.addDecl("x", new Sym("int"));
        symTable.addDecl("y", new Sym("bool"));
        symTable.addScope();
        symTable.addDecl("z", new Sym("void"));
        symTable.addScope();
        symTable.addDecl("q", new Sym("double"));
      } catch (Exception e) {
        error("SymTable.addDecl, unexpected exception: ", e.toString());
      }
      symTable.print();

      for (int i = 0; i < 3; i++) {
        try {
          symTable.removeScope();
        } catch (Exception e) {
          error("SymTable.removeScope, unexpected exception: ", e.toString());
        }
        symTable.print();
      }
    } catch (Exception e) {
      error("SymTable.print, unexpected exception: ", e.toString());
    }
  }
}

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: init.org --]
[-- Type: text/org; name=init.org, Size: 27565 bytes --]

#+STARTUP: overview 
#+PROPERTY: header-args :comments yes :results silent

* Repos (Elpa and Melpa)
#+BEGIN_SRC elisp
(require 'package)
(add-to-list 'package-archives
	     '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives
	     '("gnu" . "https://elpa.gnu.org/packages/"))
(package-initialize)
#+END_SRC

* Dirvish
#+BEGIN_SRC elisp
(use-package dirvish
  :init
  (dirvish-override-dired-mode)
  :custom
  ;; Go back home? Just press `bh'
  (dirvish-bookmark-entries
   '(("h" "~/"                          "Home")
     ("d" "~/Downloads/"                "Downloads")
     ("m" "/mnt/"                       "Drives")
     ("t" "~/.local/share/Trash/files/" "TrashCan")))
  ;; (dirvish-header-line-format '(:left (path) :right (free-space)))
  (dirvish-mode-line-format ; it's ok to place string inside
   '(:left (sort file-time " " file-size symlink) :right (omit yank index)))
  ;; Don't worry, Dirvish is still performant even you enable all these attributes
  (dirvish-attributes '(all-the-icons file-size collapse subtree-state vc-state git-msg))
  ;; Maybe the icons are too big to your eyes
  ;; (dirvish-all-the-icons-height 0.8)
  ;; In case you want the details at startup like `dired'
  ;; (dirvish-hide-details nil)
  :config
  (dirvish-peek-mode)
  ;; Dired options are respected except a few exceptions, see *In relation to Dired* section above
  (setq dired-dwim-target t)
  (setq delete-by-moving-to-trash t)
  ;; Enable mouse drag-and-drop files to other applications
  (setq dired-mouse-drag-files t)                   ; added in Emacs 29
  (setq mouse-drag-and-drop-region-cross-program t) ; added in Emacs 29
  ;; Make sure to use the long name of flags when exists
  ;; eg. use "--almost-all" instead of "-A"
  ;; Otherwise some commands won't work properly
  (setq dired-listing-switches
        "-l --almost-all --human-readable --time-style=long-iso --group-directories-first --no-group")
  :bind
  ;; Bind `dirvish|dirvish-side|dirvish-dwim' as you see fit
  (("C-c f" . dirvish-fd)
   :map dired-mode-map ; Dirvish respects all the keybindings in this map
   ("<prior>" . dired-up-directory)
   ;; ("j" . dired-next-line)
   ;; ("k" . dired-previous-line)
   ;; ("l" . dired-find-file)
   ;; ("i" . wdired-change-to-wdired-mode)
   ;; ("." . dired-omit-mode)
   ("b"   . dirvish-bookmark-jump)
   ("f"   . dirvish-file-info-menu)
   ("y"   . dirvish-yank-menu)
   ("N"   . dirvish-narrow)
   ("^"   . dirvish-history-last)
   ("s"   . dirvish-quicksort) ; remapped `dired-sort-toggle-or-edit'
   ("?"   . dirvish-dispatch)  ; remapped `dired-summary'
   ("TAB" . dirvish-subtree-toggle)
   ("SPC" . dirvish-history-jump)
   ("M-n" . dirvish-history-go-forward)
   ("M-p" . dirvish-history-go-backward)
   ("M-l" . dirvish-ls-switches-menu)
   ("M-m" . dirvish-mark-menu)
   ("M-f" . dirvish-toggle-fullscreen)
   ("M-s" . dirvish-setup-menu)
   ("M-e" . dirvish-emerge-menu)
   ("M-j" . dirvish-fd-jump)))
#+END_SRC

* Yasnippet
Also make sure to lookup yasnippet-snippets which has a great collection of snippets
https://github.com/AndreaCrotti/yasnippet-snippets

ivy-yasnippet will show you the available snippets for the current major mode you are in
and will insert them.
#+BEGIN_SRC elisp
(yas-global-mode 1)
(setq yas-indent-line nil)
(global-set-key (kbd "C-c i") 'ivy-yasnippet)
#+END_SRC

* Org Roam
#+BEGIN_SRC elisp
(use-package org-roam
	     :ensure t
	     :custom
	     (org-roam-directory (file-truename "~/Documents/roam-notes"))
	     :bind (("C-c n l" . org-roam-buffer-toggle)
		    ("C-c n f" . org-roam-node-find)
		    ("C-c n g" . org-roam-graph)
		    ("C-c n i" . org-roam-node-insert)
		    ("C-c n c" . org-roam-capture)
		    ;;Daily
		    ("C-c n j" . org-roam-dailies-capture-today))
	     :config
	     (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
	     (org-roam-db-autosync-mode)
	     (require 'org-roam-protocol))
#+END_SRC

* Miscellaneous Org Stuff
#+BEGIN_SRC elisp
(setq org-src-preserve-indentation t)

; org-fragtog makes it so you can automatically preview LaTeX without having to do anything
(add-hook 'org-mode-hook 'org-fragtog-mode)
;(plist-put org-format-latex-options :scale 2)
;(after! org (plist-put org-format-latex-options :scale 1.5))
(font-lock-add-keywords 'org-mode
			'(("^ *\\([-]\\) "
			   (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))
(require 'org-superstar)
(add-hook 'org-mode-hook (lambda () (org-superstar-mode 1)))
;;hides markup emphasis like *dd*
(setq org-hide-emphasis-markers t)
;; Agenda
(setq org-agenda-files "~/Documents/Agenda/agenda.org")
#+END_SRC

* Flyspell
#+BEGIN_SRC elisp
(flyspell-mode)
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)
#+END_SRC
* Hyperbole
#+BEGIN_SRC elisp
(hyperbole-mode 1)
#+END_SRC

* Elfeed
#+BEGIN_SRC elisp
(setq elfeed-feeds
      '(("https://ooohspooky.libsyn.com/rss" AdamKnox)
	("https://godotengine.org/rss.xml" Godot)
	("https://stackabuse.com/rss/" StackAbuse)
	("https://opensource.com/feed" OpenSource)
	("https://daverupert.com/atom.xml" DaveRupert)
	("https://feed.podbean.com/mateitsasurething/feed.xml" Wolfe)
	("https://www.omnycontent.com/d/playlist/e73c998e-6e60-432f-8610-ae210140c5b1/0c6fc944-eaa5-4022-8e77-ae3300346d76/45a735b6-e1b8-49f9-a595-ae3300346d84/podcast.rss" Scrubs)))

(require 'elfeed-org)
(require 'elfeed-goodies)
(elfeed-goodies/setup)

(global-set-key (kbd "C-x w") 'elfeed)
(elfeed-org)
(setq rmh-elfeed-org-files (list "~/.emacs.d/elfeed-dashboard.org"))

(use-package elfeed-dashboard
  :ensure t
  :config
  (setq elfeed-dashboard-file "~/elfeed-dashboard.org")
  ;; update feed counts on elfeed-quit
  (advice-add 'elfeed-search-quit-window :after #'elfeed-dashboard-update-links))

;;; g = refresh view
;;; G = fetch feed updates
;;; s = Update search filter
;;; c = clear search filter
#+END_SRC

* EMMS
#+BEGIN_SRC elisp
; https://www.draketo.de/software/emacs-tipps#elfeed-emms
(use-package emms
  :ensure t
  :config)
(global-set-key (kbd "C-x p") 'ivy-emms)
(require 'emms-setup)
(require 'emms-player-mplayer)
(emms-all)
(setq emms-player-list '(
			 emms-player-mpg321
			 emms-player-ogg123
			 emms-player-mplayer))
(defun emms-player-mplayer-volume(amount)
  (process-send-string
   emms-player-simple-process-name
   (format "volume %d\n" amount)))
(setq emms-volume-change-function 'emms-player-mplayer-volume)
(emms-default-players)
;(emms-add-directory-tree "~/Music/")
;(emms-add-directory-tree "~/Downloads/")
#+END_SRC

* Meow (Modal Editing)
#+BEGIN_SRC elisp
(defun meow-setup ()
  (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwerty)
  (meow-motion-overwrite-define-key
   '("k" . meow-next)
   '("j" . meow-prev)
   '("<escape>" . ignore))
  (meow-leader-define-key
   ;; SPC j/k will run the original command in MOTION state.
   '("j" . "H-j")
   '("k" . "H-k")
   ;; Use SPC (0-9) for digit arguments.
   '("1" . meow-digit-argument)
   '("2" . meow-digit-argument)
   '("3" . meow-digit-argument)
   '("4" . meow-digit-argument)
   '("5" . meow-digit-argument)
   '("6" . meow-digit-argument)
   '("7" . meow-digit-argument)
   '("8" . meow-digit-argument)
   '("9" . meow-digit-argument)
   '("0" . meow-digit-argument)
   '("/" . meow-keypad-describe-key)
   '("?" . meow-cheatsheet))
  (meow-normal-define-key
   '("0" . meow-expand-0)
   '("9" . meow-expand-9)
   '("8" . meow-expand-8)
   '("7" . meow-expand-7)
   '("6" . meow-expand-6)
   '("5" . meow-expand-5)
   '("4" . meow-expand-4)
   '("3" . meow-expand-3)
   '("2" . meow-expand-2)
   '("1" . meow-expand-1)
   '("-" . negative-argument)
   '(";" . meow-reverse)
   '("," . meow-inner-of-thing)
   '("." . meow-bounds-of-thing)
   '("[" . meow-beginning-of-thing)
   '("]" . meow-end-of-thing)
   '("a" . meow-append)
   '("A" . meow-open-below)
   '("b" . meow-back-word)
   '("B" . meow-back-symbol)
   '("c" . meow-change)
   '("d" . meow-delete)
   '("D" . meow-backward-delete)
   '("e" . meow-next-word)
   '("E" . meow-next-symbol)
   '("f" . meow-find)
   '("g" . meow-cancel-selection)
   '("G" . meow-grab)
   '("h" . meow-left)
   '("H" . meow-left-expand)
   '("i" . meow-insert)
   '("I" . meow-open-above)
   '("j" . meow-next)
   '("J" . meow-next-expand)
   '("k" . meow-prev)
   '("K" . meow-prev-expand)
   '("l" . meow-right)
   '("L" . meow-right-expand)
   '("m" . meow-join)
   '("n" . meow-search)
   '("o" . meow-block)
   '("O" . meow-to-block)
   '("p" . meow-yank)
   '("q" . meow-quit)
   '("Q" . meow-goto-line)
   '("r" . meow-replace)
   '("R" . meow-swap-grab)
   '("s" . meow-kill)
   '("t" . meow-till)
   '("u" . meow-undo)
   '("U" . meow-undo-in-selection)
   '("v" . meow-visit)
   '("w" . meow-mark-word)
   '("W" . meow-mark-symbol)
   '("x" . meow-line)
   '("X" . meow-goto-line)
   '("y" . meow-save)
   '("Y" . meow-sync-grab)
   '("z" . meow-pop-selection)
   '("'" . repeat)
   '("<escape>" . ignore)))

(setq meow-cursor-type-normal 'hbar)
(setq meow-cursor-type-insert 'box)

(require 'meow)
(meow-setup)
(meow-global-mode 1)
#+END_SRC
* :TODO: Setup MU4E
#+BEGIN_SRC elisp
;;;;;;;;;;;;;;;;;;;mu4e;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/mu4e")
;(require 'mu4e)

;(mu4e-alert-set-default-style 'libnotify)
;(add-hook 'after-init-hook 'mu4e-alert-enable-notifications)
;(mu4e-alert-notifications)
#+END_SRC

* Random Stuff
Shift and arrow key changes windows
#+BEGIN_SRC elisp
(when (fboundp 'windmove-default-keybindings)
  (windmove-default-keybindings))
#+END_SRC

Kills the scratch buffer on launch and changes a few UI things.
#+BEGIN_SRC elisp
(kill-buffer "*scratch*")
;(setq inhibit-splash-screen t)
(setq inhibit-startup-screen t)
(scroll-bar-mode -1)
(menu-bar-mode -1)
(tool-bar-mode -1)
(display-time-mode t)
;;Getting rid of line wrapping.
(set-default 'truncate-lines t)
;;;;;;;;;;;;;;; turn off the beeping ;;;;;;;;;;;
(setq visible-bell 1)

;;(global-linum-mode t)
;; replacing linum-mode with display-line-mode as it follows the theme
(global-display-line-numbers-mode t)
(global-set-key (kbd "C-x i") (lambda () (interactive)(find-file "~/.emacs.d/init.org")))
#+END_SRC

* Diary
#+BEGIN_SRC elisp
;desktop notifications
(require 'notifications)

(defcustom appt-notification-bus :session
  "dbus notifications"
  :version "29.05"
  :group 'appt-notification
  :type '(choice (const :tag "Session bus" :session) string))

(defun user/appt-display (min-to-app new-time msg)
  "sends notifications"
  (notifications-notify :bus appt-notification-bus
			:title (format "Appointment in %s minutes" min-to-app)
			:body (format "%s" msg)
			:replaces-id nil
			:app-icon notifications-application-icon
			:timeout 8000
			:desktop-entry "diary"))

(setq appt-disp-window-function (function user/appt-display))

(setq-default diary-file "~/.emacs.d/diary"
	      appt-display-format 'window
	      appt-display-duration 60
	      appt-audible t
	      appt-display-interval 15
	      appt-message-warning-time 15
	      display-time-24hr-format t
	      display-time-day-and-date t)

(appt-activate t)

;imports ical file, takes a long time since my ical is huge from old events
;(icalendar-import-file "~/.local/share/evolution/calendar/system/calendar.ics"
;		       "~/.emacs.d/diary")

#+END_SRC

* Emojify
#+BEGIN_SRC elisp
;;;;displays emojis for weather
(emojify-mode 1)
(emojify-mode-line-mode 1)
#+END_SRC
* Dashboard
#+BEGIN_SRC elisp
;; Set the title
(require 'dashboard)
(setq dashboard-week-agenda t)
(setq dashboard-banner-logo-title "I'm using Linux. A library that emacs uses to communicate with Intel hardware.") 
;(setq dashboard-startup-banner "~/Downloads/rsz_emacs-colorful.png")
(setq dashboard-startup-banner "~/Pictures/emacs-colorful.png")
;(setq dashboard-startup-banner 'official)
(setq dashboard-set-heading-icons t)
(setq dashboard-set-file-icons t)
(setq dashboard-set-navigator t)
(setq dashboard-center-content t)
;; To disable shortcut "jump" indicators for each section, set
(setq dashboard-show-shortcuts nil)

(dashboard-setup-startup-hook)

(auto-image-file-mode 1)

(use-package page-break-lines
  :ensure t
  :demand t)

(global-page-break-lines-mode 1)
#+END_SRC

* SVG Tag
#+BEGIN_SRC elisp
(defconst date-re "[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}")
(defconst time-re "[0-9]\\{2\\}:[0-9]\\{2\\}")
(defconst day-re "[A-Za-z]\\{3\\}")
(defconst day-time-re (format "\\(%s\\)? ?\\(%s\\)?" day-re time-re))

(defun svg-progress-percent (value)
  (svg-image (svg-lib-concat
              (svg-lib-progress-bar (/ (string-to-number value) 100.0)
                                nil :margin 0 :stroke 2 :radius 3 :padding 2 :width 11)
              (svg-lib-tag (concat value "%")
                           nil :stroke 0 :margin 0)) :ascent 'center))

(defun svg-progress-count (value)
  (let* ((seq (mapcar #'string-to-number (split-string value "/")))
         (count (float (car seq)))
         (total (float (cadr seq))))
  (svg-image (svg-lib-concat
              (svg-lib-progress-bar (/ count total) nil
                                    :margin 0 :stroke 2 :radius 3 :padding 2 :width 11)
              (svg-lib-tag value nil
                           :stroke 0 :margin 0)) :ascent 'center)))

;Setting my own face
;(defface myface '((t (:inherit org-todo) :height 1.0 :background "#957DAD")) "Face for todo")
(defface pastelpurple '((t (:inherit org-todo :height 2.0 :foreground "#957DAD"))) "Face for todo")
(defface pastelgreen '((t (:inherit org-todo :height 2.0 :foreground "#B0EB93"))) "Face for WIP")
(defface pastelblue '((t (:inherit org-todo :height 2.0 :foreground "#B3E3DA"))) "Face for DONE")
(defface pastelred '((t (:inherit org-todo :height 2.0 :foreground "#F98284"))) "Face for tags")
(defface pastelpink '((t (:inherit org-todo :height 2.0 :foreground "#FEAAE4"))) "Face for Date")


(setq svg-tag-tags
      `(
        ;; Org tags :THIS:
        ("\\(:[A-Za-z0-9]+:\\)" . ((lambda (tag) (svg-tag-make tag :beg 1 :end -1 :inverse t :face 'pastelred))))
	
	;(1)
	;("\([0-;9a-zA-Z]\)" . ((lambda (tag)
        ;                        (svg-tag-make tag :beg 1 :end -1 :radius 12))))

	;(09)
        ;("\([0-9a-zA-Z][0-9a-zA-Z]\)" . ((lambda (tag)
        ;                                   (svg-tag-make tag :beg 1 :end -1 :radius 8))))

	;(007)
        ;("\([0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z]\)" . ((lambda (tag)
        ;                                   (svg-tag-make tag :beg 1 :end -1 :radius 8))))

	;Unsure?
	;("|[0-9a-zA-Z- ]+?|" . ((lambda (tag)
        ;                          (svg-tag-make tag :face 'font-lock-comment-face
        ;                                        :margin 0 :beg 1 :end -1))))
	
        ;; Task priority [#a]
        ("\\[#[a-zA-Z]\\]" . ( (lambda (tag)
                              (svg-tag-make tag :face 'org-priority 
                                            :beg 2 :end -1 :margin 0 :inverse t))))

        ;; Progress [1/3] or [45%]
        ("\\(\\[[0-9]\\{1,3\\}%\\]\\)" . ((lambda (tag)
                                            (svg-progress-percent (substring tag 1 -2)))))
        ("\\(\\[[0-9]+/[0-9]+\\]\\)" . ((lambda (tag)
                                          (svg-progress-count (substring tag 1 -1)))))
        
        ;; Org TAGS
        (":TODO:" . ((lambda (tag) (svg-tag-make "TODO" :inverse t :face 'pastelpurple))))
        (":WIP:" . ((lambda (tag) (svg-tag-make "WIP" :inverse t :face 'pastelgreen))))
        (":DONE:" . ((lambda (tag) (svg-tag-make "DONE" :inverse t :face 'pastelblue))))
        (":NOTE:" . ((lambda (tag) (svg-tag-make "NOTE" :inverse t :face 'org-todo))))
        ("SCHEDULED:" . ((lambda (tag) (svg-tag-make "SCHEDULED" :inverse t :face 'org-tag))))
        ("DEADLINE:" . ((lambda (tag) (svg-tag-make "DEADLINE" :inverse t :face 'org-tag))))
        ("+BEGIN_SRC" . ((lambda (tag) (svg-tag-make "BEGIN" :inverse t :face 'org-tag))))
        ("+END_SRC" . ((lambda (tag) (svg-tag-make "END" :inverse t :face 'org-tag))))
        ("+RESULTS:" . ((lambda (tag) (svg-tag-make "RESULTS" :inverse t :face 'org-tag))))
        ("+title" . ((lambda (tag) (svg-tag-make "TITLE" :inverse t :face 'org-tag))))
        ("+BEGIN:" . ((lambda (tag) (svg-tag-make "BEGIN" :inverse t :face 'org-tag))))
        ("+CAPTION:" . ((lambda (tag) (svg-tag-make "CAPTION" :inverse t :face 'org-tag))))
        ("+END:" . ((lambda (tag) (svg-tag-make "END" :inverse t :face 'org-tag))))
	(":X" . ((lambda (tag) (svg-tag-make "[X]" :inverse t :face 'org-todo))))
        (":-" . ((lambda (tag) (svg-tag-make "[-]" :inverse t :face 'org-tag))))
	
        ;; Citation of the form [cite:@Knuth:1984] 
        ("\\(\\[cite:@[A-Za-z]+:\\)" . ((lambda (tag)
                                          (svg-tag-make tag
                                                        :inverse t
                                                        :beg 7 :end -1
                                                        :crop-right t))))
        ("\\[cite:@[A-Za-z]+:\\([0-9]+\\]\\)" . ((lambda (tag)
                                                (svg-tag-make tag
                                                              :end -1
                                                              :crop-left t))))


	;;; Works for stuff like :XXX|YYY:
	("\\(:[A-Z]+\\)\|[a-zA-Z#0-9]+:" . ((lambda (tag)
                                           (svg-tag-make tag :beg 1 :inverse t
                                                          :margin 0 :crop-right t))))        

        (":[A-Z]+\\(\|[a-zA-Z#0-9]+:\\)" . ((lambda (tag)
                                           (svg-tag-make tag :beg 1 :end -1
                                                         :margin 0 :crop-left t))))
	;; Active date (with or without day name, with or without time)
        (,(format "\\(<%s>\\)" date-re) .
         ((lambda (tag)
            (svg-tag-make tag :beg 1 :end -1 :margin 0 :face 'pastelpink :inverse t))))
        (,(format "\\(<%s \\)%s>" date-re day-time-re) .
         ((lambda (tag)
            (svg-tag-make tag :beg 1 :inverse t :crop-right t :margin 0 :face 'pastelpink))))
        (,(format "<%s \\(%s>\\)" date-re day-time-re) .
         ((lambda (tag)
            (svg-tag-make tag :end -1 :inverse nil :crop-left t :margin 0 :face 'pastelpink))))))

        ;; Inactive date  (with or without day name, with or without time)
         ;(,(format "\\(\\[%s\\]\\)" date-re) .
         ; ((lambda (tag)
         ;    (svg-tag-make tag :beg 1 :end -1 :margin 0 :face 'org-date))))
         ;(,(format "\\(\\[%s \\)%s\\]" date-re day-time-re) .
         ; ((lambda (tag)
         ;    (svg-tag-make tag :beg 1 :inverse nil :crop-right t :margin 0 :face 'org-date))))
         ;(,(format "\\[%s \\(%s\\]\\)" date-re day-time-re) .
         ; ((lambda (tag)
         ;    (svg-tag-make tag :end -1 :inverse t :crop-left t :margin 0 :face 'org-date))))))

(require 'svg-tag-mode)
(global-svg-tag-mode 1)
(use-package svg-lib)
#+END_SRC

* Ivy, Smex, Orderless and Swiper
#+BEGIN_SRC elisp
(ivy-mode 1)

(require 'smex)
(global-set-key (kbd "M-x") 'smex)

(global-set-key (kbd "C-s") 'swiper)


(use-package orderless
  :ensure t
  :custom
  (completion-styles '(orderless basic))
  (completion-category-overrides '((file (styles basic partial-completion)))))

(setq ivy-re-builders-alist '((t . orderless-ivy-re-builder)))
(add-to-list 'ivy-highlight-functions-alist '(orderless-ivy-re-builder . orderless-ivy-highlight))

#+END_SRC
* Centaur Tabs
#+BEGIN_SRC elisp
(use-package centaur-tabs
  :demand
  :config
  (centaur-tabs-mode t)
  :bind
  ("C-<prior>" . centaur-tabs-backward)
  ("C-<next>" . centaur-tabs-forward))
(centaur-tabs-headline-match)
(setq centaur-tabs-style "bar")
(setq centaur-tabs-height 12)
(setq centaur-tabs-set-icons t)
(setq centaur-tabs-close-button "X")
(setq centaur-tabs-set-modified-marker t)
(setq centaur-tabs-modified-marker "*")
(setq centaur-tabs-set-bar 'left)
#+END_SRC

* LSP-Mode (Development in general)
Commenting out the lines with a number afterwards because I am trying to switch
to LSP-Bridge to see if it solves the issue of my Emacs freezing.
#+BEGIN_SRC elisp
(use-package projectile)
(use-package flycheck :ensure t :init (global-flycheck-mode))
(use-package yasnippet :config (yas-global-mode))
;(use-package lsp-ui) 1
(use-package which-key :config (which-key-mode))
;; LSP-Java freezes my machine so it's currently commented out
;(use-package lsp-java :config (add-hook 'java-mode-hook 'lsp))
;(use-package dap-mode :after lsp-mode :config (dap-auto-configure-mode)) 1

;;(use-package lsp-mode 1
;;  :hook ((lsp-mode . lsp-enable-which-key-integration))
;;  :config
;;  (setq
;;   lsp-enable-file-watchers nil
;;   lsp-headerline-breadcrumb-enable nil
;;   )
;;  ;; Performance tweaks, see
;;  ;; https://github.com/emacs-lsp/lsp-mode#performance
;;  (setq gc-cons-threshold 100000000)
;;  (setq read-process-output-max (* 1024 1024)) ;; 1mb
;;  (setq lsp-idle-delay 0.500)
;;  )

(require 'go-mode)

;(require 'company) 1

;(add-hook 'after-init-hook 'global-company-mode) 1

;(use-package company-box 1
;  :hook (company-mode . company-box-mode))

;; lsp extras 1
;;(setq lsp-ui-sideline-enable t
;;      lsp-ui-sideline-show-symbol t
;;      lsp-ui-sideline-show-hover t
;;      lsp-ui-sideline-show-flycheck t
;;      lsp-ui-sideline-show-code-actions nil
;;      lsp-ui-sideline-show-diagnostics nil)


;; Elpy
(use-package elpy
  :ensure t
  :init
  (elpy-enable))

;; TabNine integration for code completion
;;(use-package company-tabnine :ensure t) 1
;;(require 'company-tabnine) 1
;;(add-to-list 'company-backends #'company-tabnine) 1
;; Trigger completion immediately.
;;(setq company-idle-delay 0.15) 1

;; Number the candidates (use M-1, M-2 etc to select completions).
;;(setq company-show-numbers t) 1

;; JS development
;;(use-package frontside-javascript 1
;;  :init (frontside-javascript))

#+END_SRC
* Font
#+BEGIN_SRC elisp
;Works with Options->Set Default Font
(set-face-attribute 'default nil :family "Iosevka")
;(set-frame-font "Iosevka 18" nil t)
#+END_SRC

* Golden Ratio
Makes it so the buffer you are focused on is larger than the ones not focused on.
#+BEGIN_SRC elisp
; https://github.com/roman/golden-ratio.el
(golden-ratio-mode 1)
#+END_SRC
* Babel
#+BEGIN_SRC elisp
;; Org Babel
;(load-library 'ob-rust)
(org-babel-do-load-languages
 'org-babel-load-languages
 '((python . t)))
;   (octave . t)
;   (rust . t)))
#+END_SRC
* Yasnippet
#+BEGIN_SRC elisp
(require 'yasnippet)
#+END_SRC

* Perspective
#+BEGIN_SRC elisp
(require 'perspective)
(global-set-key (kbd "C-x C-b") 'persp-list-buffers)
(global-set-key (kbd "C-x C-p") 'persp-switch)
(customize-set-variable 'persp-mode-prefix-key (kbd "C-c M-p"))
(persp-mode)
#+END_SRC

* Marginalia
#+BEGIN_SRC elisp
(marginalia-mode 1)
#+END_SRC
* Doom Modeline
#+BEGIN_SRC elisp
(use-package doom-modeline
  :ensure t
  :init (doom-modeline-mode 1))
#+END_SRC
* Centered Cursor Mode
#+BEGIN_SRC elisp
(use-package centered-cursor-mode
  :demand
  :config
  ;; Optional, enables centered-cursor-mode in all buffers.
  (global-centered-cursor-mode))
#+END_SRC
* Built-In functions (Electric pair and which function)
#+BEGIN_SRC elisp
;;; Electric-pair mode (Matches parens and brackets)
(electric-pair-mode 1)

;; top-bar which function you're cuirrently in
(which-function-mode)
#+END_SRC

* Rainbow Delimiter Mode
Rainbow delimiter mode changes colors of delimites to match their partner
#+BEGIN_SRC elisp
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
#+END_SRC
* Line-Reminder Mode
Line-reminder-mode, basically shows what you've changed in your current session

One thing to note though is that with the current theme setup, there is an issue
with seeing the yellow marker so I changed that value to be #DDE165. It is apparently
being worked on upstream in the theme, but hasn't been finished yet.

:TODO: Figure out how to change the identifier to the right hand side of the fringe???
#+BEGIN_SRC elisp
(require 'indicators)
(use-package line-reminder
  :ensure t
  :init
  (setq line-reminder-show-option 'indicators)
  ;; Customize the modified sign.
  ;;(setq line-reminder-modified-sign "▐")  ; not needed
  ;;Customize the saved sign.
  ;;(setq line-reminder-saved-sign "▐")  ; not needed
  ;;Customize string on the right/left side of the line number.
  (setq line-reminder-linum-left-string "")
  (setq line-reminder-linum-right-string " ")
  :config
  (add-hook 'prog-mode-hook
            (function
             (lambda ()
               (line-reminder-mode t)
               (setq line-reminder-show-option 'indicators)))))
(global-line-reminder-mode t)
#+END_SRC

* Origami mode
This is used for code folding, though I do think Tree-Sitter can do the same thing so I may get
rid of this. Not exactly sure yet though since I haven't done that yet with tree-sitter
#+BEGIN_SRC elisp
;;(global-origami-mode 1)
;;(global-set-key (kbd "C-c C-c") 'origami-close-all-nodes)
;;(global-set-key (kbd "C-c C-o") 'origami-open-all-nodes)
;;(global-set-key (kbd "C-c c") 'origami-close-node-recursively)
;;(global-set-key (kbd "C-c o") 'origami-open-node-recursively)
#+END_SRC
* Tree-Sitter Mode
:IMPORTANT: to view AST run tree-sitter-debug-mode

:TODO: Work with tree queries with https://emacs-tree-sitter.github.io/getting-started/#play-around-with-tree-queries
run tree-sitter-query-builder and use an example from below
 Python:
 (class_definition (identifier) @class)
 (function_definition (identifier) @func)

Rust:
 (function_item (identifier) @func)
 (impl_item (type_identifier) @impl)

Javascript:
 (function_declaration (identifier) @func)
 (variable_declarator (identifier) @var)

Great talk found here
https://www.youtube.com/watch?v=MZPR_SC9LzE

#+BEGIN_SRC elisp
(require 'tree-sitter)
(require 'tree-sitter-langs)

;; Turns on tree-sitter-mode globaly and turns on the highlighting for it
(global-tree-sitter-mode)
(add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode)
;; To check supported major modes run tree-sitter-major-mode-language-alist

(tree-sitter-require 'rust)
(tree-sitter-require 'python)
(tree-sitter-require 'java)
(tree-sitter-require 'javascript)

; Code folding
(use-package ts-fold
  :load-path "~/.emacs.d/ts-fold")

(use-package ts-fold-indicators
   :load-path "~/.emacs.d/ts-fold")

;; Identifier for folding
;(use-package ts-fold-indicators
;  :straight (ts-fold-indicators :type git :host github :repo "emacs-tree-sitter/ts-fold"))
;(require 'ts-fold)
(global-ts-fold-mode 1)
(global-ts-fold-indicators-mode 1)

(add-hook 'tree-sitter-after-on-hook #'ts-fold-indicators-mode)
;(setq ts-fold-indicators-fringe 'right-fringe)
(setq ts-fold-indicators-priority 30)

(setq ts-fold-indicators-face-function
      (lambda (pos &rest _)
        ;; Return the face of it's function.
        (line-reminder--get-face (line-number-at-pos pos t))))

(advice-add 'line-reminder-transfer-to-saved-lines :after
            ;; Refresh indicators for package `ts-fold'.
            #'ts-fold-indicators-refresh)

;; :TODO: As it turns out, most of the major modes I use have a keybinding for both the open/close-all function
;; bindings I have below.
(global-set-key (kbd "C-c C-c") 'ts-fold-close-all)
(global-set-key (kbd "C-c C-o") 'ts-fold-open-all)
(global-set-key (kbd "C-c c") 'ts-fold-close)
(global-set-key (kbd "C-c o") 'ts-fold-open-recursively) ;; might change to ts-fold-open

;; Comment summaries when folded
;(setq ts-fold-summary-show nil)
(setq ts-fold-summary-max-length 60)
#+END_SRC


^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2024-04-19 15:59 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-11 18:16 bug#61436: Emacs Freezing With Java Files Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-12  0:24 ` Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-12  6:30   ` Eli Zaretskii
2023-02-12 16:52     ` Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-12 17:05       ` Eli Zaretskii
2023-02-12 17:11         ` Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-09 20:26           ` Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-10 20:58             ` Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-11  7:28               ` Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-11 10:17                 ` Robert Weiner
2023-10-11 19:38                   ` Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-11 20:07                     ` Robert Weiner
2023-10-11 21:43                     ` Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-11 22:03                     ` Alan Mackenzie
2023-10-12 19:58                       ` Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-13 12:41                         ` Alan Mackenzie
2023-10-13 18:02                           ` Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-13 20:42                           ` Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-14 19:41                             ` Alan Mackenzie
2023-10-15 10:20                               ` Robert Weiner
2023-10-16 14:05                                 ` Alan Mackenzie
2023-10-16 19:10                                   ` Robert Weiner
2023-10-21 22:14                                   ` Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-22 14:15                                     ` Alan Mackenzie
2023-10-22 17:17                                       ` Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors
     [not found]                                         ` <CA+OMD9hgM_NX7GmeW8ph5fBW6SkFGogf4W4JOO5o62H3X15WHw@mail.gmail.com>
2024-04-17 13:22                                           ` Alan Mackenzie
     [not found]                                           ` <Zh_JagP5xaaXJMOo@ACM>
2024-04-17 18:50                                             ` Alan Mackenzie
2024-04-17 22:24                                               ` Robert Weiner
2024-04-19  2:19                                               ` Robert Weiner
2024-04-19  4:40                                                 ` Robert Weiner
2024-04-19 15:59                                                   ` Alan Mackenzie
2024-04-19  2:58                           ` Robert Weiner
2023-02-12  6:00 ` Eli Zaretskii

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).