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

* bug#61436: Emacs Freezing With Java Files
  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  6:00 ` Eli Zaretskii
  1 sibling, 1 reply; 33+ messages in thread
From: Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-12  0:24 UTC (permalink / raw)
  To: Hank Greenburg; +Cc: 61436

[-- Attachment #1: Type: text/plain, Size: 2979 bytes --]

To follow up on this, somehow disabling which-function-mode from my config has solved the problem. That doesn't make sense though because I didn't add that until after it had frozen in the first place. I know that for certain because I had to use IntelliJ and got the idea for using which-function-mode from IntelliJ.

To clarify, this froze every single time I tried to edit the file no matter what modes I had turned on or off. It happened at least 40 times in total and never once was I able to actually edit the file within Emacs. After disabling which-function-mode though I have restarted Emacs a few times, written in the file, scrolled though it all without a single hiccup.

So my problem is seemingly solved but there is an underlying bug somewhere that I'm not really able to isolate aside from disabling which-function-mode.

------- Original Message -------
On Saturday, February 11th, 2023 at 12:16 PM, Hank Greenburg via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> wrote:

> 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 #2: Type: text/html, Size: 5176 bytes --]

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

* bug#61436: Emacs Freezing With Java Files
  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:00 ` Eli Zaretskii
  1 sibling, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2023-02-12  6:00 UTC (permalink / raw)
  To: Hank Greenburg; +Cc: 61436

> Date: Sat, 11 Feb 2023 18:16:41 +0000
> From:  Hank Greenburg via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> 
> 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. 

I confirm that the issue doesn't happen with "emacs -Q" and the file
you posted.  So some of your customizations trigger the problem, and
we must find out which one(s).  Can you try selectively enabling only
parts of your init files to find which customizations are the reason?
If your customizations are not too many, starting "emacs -Q" and then
evaluating the customizations one by one could be a good way of
finding the culprit(s).  Another possibility is bisecting:
successively divide the init file in two halves and see which half
causes the problem, then divide that half in tow, etc. etc., until you
get to a small enough part you can post here (or figure out yourself).

Thanks.





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2023-02-12  6:30 UTC (permalink / raw)
  To: Hank Greenburg; +Cc: 61436

> Cc: 61436@debbugs.gnu.org
> Date: Sun, 12 Feb 2023 00:24:49 +0000
> From:  Hank Greenburg via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> 
> To follow up on this, somehow disabling which-function-mode from my config has solved the problem. That
> doesn't make sense though because I didn't add that until after it had frozen in the first place. I know that for
> certain because I had to use IntelliJ and got the idea for using which-function-mode from IntelliJ. 
> 
> To clarify, this froze every single time I tried to edit the file no matter what modes I had turned on or off. It
> happened at least 40 times in total and never once was I able to actually edit the file within Emacs. After
> disabling which-function-mode though I have restarted Emacs a few times, written in the file, scrolled though
> it all without a single hiccup. 
> 
> So my problem is seemingly solved but there is an underlying bug somewhere that I'm not really able to
> isolate aside from disabling which-function-mode. 

If I visit the file you posted, and then turn on which-function-mode
in it, I cannot reproduce the freezes.  Scrolling through the file
becomes slower, but nowhere near "freezing".

Do you see something different when you enable just
which-function-mode in "emacs -Q"?





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-12 16:52 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 61436

I was just able to reproduce this 5 times in a row with doing the steps below. 

Launch with emacs -Q

org-babel-execute-src-block for the Repos block and Hyperbole. The Hyperbole block won't work unless you do the Repos block first.

Go to the Java file. Hold CTRL + Up/Down Arrow keys to quickly move through the file. 

This works just fine until which-function-mode is activated. After that is activated I can scroll through maybe twice before it freezes. 

It almost always happens after hitting the end of the file, and the first jump up after that. Or at least it has happened 4/5 times by doing that. The other time I avoided the end of the file to see if that was the trigger and it still froze. 



------- Original Message -------
On Sunday, February 12th, 2023 at 12:30 AM, Eli Zaretskii <eliz@gnu.org> wrote:


> 
> 
> > Cc: 61436@debbugs.gnu.org
> 
> > Date: Sun, 12 Feb 2023 00:24:49 +0000
> > From: Hank Greenburg via "Bug reports for GNU Emacs,
> > the Swiss army knife of text editors" bug-gnu-emacs@gnu.org
> > 
> > To follow up on this, somehow disabling which-function-mode from my config has solved the problem. That
> > doesn't make sense though because I didn't add that until after it had frozen in the first place. I know that for
> > certain because I had to use IntelliJ and got the idea for using which-function-mode from IntelliJ.
> > 
> > To clarify, this froze every single time I tried to edit the file no matter what modes I had turned on or off. It
> > happened at least 40 times in total and never once was I able to actually edit the file within Emacs. After
> > disabling which-function-mode though I have restarted Emacs a few times, written in the file, scrolled though
> > it all without a single hiccup.
> > 
> > So my problem is seemingly solved but there is an underlying bug somewhere that I'm not really able to
> > isolate aside from disabling which-function-mode.
> 
> 
> If I visit the file you posted, and then turn on which-function-mode
> in it, I cannot reproduce the freezes. Scrolling through the file
> becomes slower, but nowhere near "freezing".
> 
> Do you see something different when you enable just
> which-function-mode in "emacs -Q"?
>





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2023-02-12 17:05 UTC (permalink / raw)
  To: Hank Greenburg; +Cc: 61436

> Date: Sun, 12 Feb 2023 16:52:51 +0000
> From: Hank Greenburg <hank.greenburg@protonmail.com>
> Cc: 61436@debbugs.gnu.org
> 
> Launch with emacs -Q
> 
> org-babel-execute-src-block for the Repos block and Hyperbole. The Hyperbole block won't work unless you do the Repos block first.

Sorry, I don't understand: what is "the Repos block", and what is the
"Hyperbole block"?  What do I need to do after starting "emacs -Q" to
reproduce what you describe above? which commands to type?





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Hank Greenburg via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-12 17:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 61436

[-- Attachment #1: Type: text/plain, Size: 1582 bytes --]

Sorry, by blocks I mean the org-mode code blocks that are under the headers "Repos (Elpa and Melpa)" and "Hyperbole" in the init.org file I sent with my first email. I've attached it again here.

Underneath those headers is an org-mode source block, if you go inside of the block and run "org-babel-execute-src-block" then say yes when it asks if you want to run the code. If you do that for Repos and Hyperbole blocks then follow the steps below.


Go to the Java file. Hold CTRL + Up/Down Arrow keys to quickly move through the file.

This works just fine until which-function-mode is activated. After that is activated I can scroll through maybe twice before it freezes.

It almost always happens after hitting the end of the file, and the first jump up after that. Or at least it has happened 4/5 times by doing that. The other time I avoided the end of the file to see if that was the trigger and it still froze.



------- Original Message -------
On Sunday, February 12th, 2023 at 11:05 AM, Eli Zaretskii <eliz@gnu.org> wrote:


> 
> 
> > Date: Sun, 12 Feb 2023 16:52:51 +0000
> 
> > From: Hank Greenburg hank.greenburg@protonmail.com
> > Cc: 61436@debbugs.gnu.org
> > 
> > Launch with emacs -Q
> > 
> > org-babel-execute-src-block for the Repos block and Hyperbole. The Hyperbole block won't work unless you do the Repos block first.
> 
> 
> Sorry, I don't understand: what is "the Repos block", and what is the
> "Hyperbole block"? What do I need to do after starting "emacs -Q" to
> reproduce what you describe above? which commands to type?

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


* 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
(require 'yasnippet)
(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)
=show-paren-context-when-offscreen= is a function to customize which makes it
so that you can see what function your current brace/paren is matching when
that function is offscreen. This only works on Emacs 29 and newer though.
#+BEGIN_SRC elisp
;;; Electric-pair mode (Matches parens and brackets)
(electric-pair-mode 1)
(setq show-paren-context-when-offscreen 'overlay)
;; 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


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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-09 20:26 UTC (permalink / raw)
  To: Hank Greenburg; +Cc: Eli Zaretskii, 61436

found 61436 29.1.50
found 61436 30.0.50
thanks

Hank Greenburg <hank.greenburg@protonmail.com> writes:
> This works just fine until which-function-mode is
> activated. After that is activated I can scroll through maybe
> twice before it freezes.

I can confirm both on emacs-29 and on master.  (Actually, I was hoping
for another case of my bug#60768 wracking havoc, but this issue is
actually something different.  Even though `beginning-of-defun' is also
involved here through `which-function' calls ...)

A slightly easier to follow reproducer:

- Ensure package "hyperbole" is installed.  (Its only role in this issue
  seems to be a "background load generator", but I'm not 100% sure
  here.)

- Save Hank's Java source P1.java to ~/tmp.

- Save the following to ~/tmp/init.el:

------------------------- snip -------------------------
(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)
(hyperbole-mode 1)
(which-function-mode 1)
------------------------- snip -------------------------

- Start emacs as

  ./src/emacs -Q -l ~/tmp/init.el ~/tmp/P1.java

  and wait for the compiler warnings to calm down.

- As Hank has recommended, forward/backward paragraph through P1.java.
  Rather soon it should hang.

And yes, it's which-function-mode which at some level inf-loops.  Maybe
the timer itself, maybe some upper layer.  If I'll find time I could try
digging into this.





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-10 20:58 UTC (permalink / raw)
  To: Hank Greenburg; +Cc: Eli Zaretskii, 61436, Mats Lidell, Bob Weiner

Jens Schmidt <jschmidt4gnu@vodafonemail.de> writes:

>   Ensure package "hyperbole" is installed.  (Its only role in this
>   issue seems to be a "background load generator", but I'm not 100%
>   sure here.)

The second part above is not true!  Hyperbole mode is the culprit,
unless proven otherwise.  Here is a 100%-freezing reproducer (with
P1.java as from the initial post):

------------------------- init.el -------------------------
(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)
;(setq hkey-init nil)
(hyperbole-mode 1)
------------------------- init.el -------------------------

Execute Emacs as:

  ./src/emacs -Q -l ~/tmp/init.el +181 ~/tmp/P1.java

That always freezes Emacs (29 and master) even before it has a chance to
display P1.java.  The freeze happens in function
`c-get-fallback-scan-pos', where the while loop inf-loops, BUT:

If you uncomment the line setting `hkey-init' to nil in init.el and
repeat: No freeze.

Not sure how to continue here - since this is a GNU ELPA package, it can
be further handled on Emacs debbugs, no?  Mats, Bob?

Disclaimer: I do not use Hyperbole as a regular user, I installed it
through `package-install' just for the purpose of this bug, as follows:

------------------------- snip -------------------------
Package hyperbole is installed.

     Status: Installed in ‘hyperbole-8.0.0/’. Delete
    Version: 8.0.0
     Commit: 4214716e06920a3e10db5811bd22a343ad6435d9
    Summary: GNU Hyperbole: The Everyday Hypertextual Information Manager
   Requires: emacs-27.0
    Website: https://www.gnu.org/software/hyperbole
   Keywords: comm convenience files frames hypermedia languages mail matching mouse multimedia outlines tools wp
 Maintainer: Bob Weiner <rsw@gnu.org>, Mats Lidell <matsl@gnu.org>
     Author: Bob Weiner
Other versions: 8.0.0 (gnu).
------------------------- snip -------------------------





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-11  7:28 UTC (permalink / raw)
  To: Jens Schmidt; +Cc: Hank Greenburg, 61436, Eli Zaretskii, Bob Weiner

Hi Jens,

Thanks for the report. Seems non trivial.

> Jens Schmidt writes:
> Jens Schmidt <jschmidt4gnu@vodafonemail.de> writes:
>
> >   Ensure package "hyperbole" is installed.  (Its only role in this
> >   issue seems to be a "background load generator", but I'm not 100%
> >   sure here.)
>
> The second part above is not true!  Hyperbole mode is the culprit,
> unless proven otherwise.  Here is a 100%-freezing reproducer (with
> P1.java as from the initial post):
>
> ------------------------- init.el -------------------------
> (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)
> ;(setq hkey-init nil)
> (hyperbole-mode 1)
> ------------------------- init.el -------------------------
>
> Execute Emacs as:
>
>   ./src/emacs -Q -l ~/tmp/init.el +181 ~/tmp/P1.java
>
> That always freezes Emacs (29 and master) even before it has a chance to
> display P1.java.  The freeze happens in function
> `c-get-fallback-scan-pos', where the while loop inf-loops, BUT:
>
> If you uncomment the line setting `hkey-init' to nil in init.el and
> repeat: No freeze.

I have tried to recreate the freezing (with 29.1 running docker) and I don't
see the exact same behavior. For me P1.java is displayed and there us no
freeze but when I try to go to top or bottom of file it freezes and I have to
hit C-g. After that it seems to work. This is just an observation. There can
be more things affected of course.

I have tried both with the hyperbole stable and devel packages and get the
same behavior. 

Note: I don't know what P1.java means here. I have picked a java file at
random that I had on my machine that is large. Is P1.java a specific file that
has been shared earlier?

> Not sure how to continue here - since this is a GNU ELPA package, it can
> be further handled on Emacs debbugs, no?  Mats, Bob?

Hyperbole has its own tracker.

https://debbugs.gnu.org/cgi/pkgreport.cgi?package=hyperbole

%% Mats





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Robert Weiner @ 2023-10-11 10:17 UTC (permalink / raw)
  To: Mats Lidell; +Cc: Hank Greenburg, Jens Schmidt, Eli Zaretskii, 61436

[-- Attachment #1: Type: text/plain, Size: 3122 bytes --]

Jens wrote:

> That always freezes Emacs (29 and master) even before it has a chance to
> display P1.java.  The freeze happens in function
> `c-get-fallback-scan-pos', where the while loop inf-loops, BUT:
>
> If you uncomment the line setting `hkey-init' to nil in init.el and
> repeat: No freeze.

As you note above, the infinite loop is coming from a Lisp function in
Emacs core, not from Hyperbole.  A Hyperbole setting may help you to see a
state reached in that function that you otherwise would not, but it is not
a Hyperbole bug; it is an unhandled state outside of Hyperbole.  When the
issue is found, we will have to work around it in Hyperbole since we
support Emacs versions back to 27.1 but that is another matter.  Thanks for
pointing it out.

-- rsw


On Wed, Oct 11, 2023 at 3:29 AM Mats Lidell <mats.lidell@lidells.se> wrote:

> Hi Jens,
>
> Thanks for the report. Seems non trivial.
>
> > Jens Schmidt writes:
> > Jens Schmidt <jschmidt4gnu@vodafonemail.de> writes:
> >
> > >   Ensure package "hyperbole" is installed.  (Its only role in this
> > >   issue seems to be a "background load generator", but I'm not 100%
> > >   sure here.)
> >
> > The second part above is not true!  Hyperbole mode is the culprit,
> > unless proven otherwise.  Here is a 100%-freezing reproducer (with
> > P1.java as from the initial post):
> >
> > ------------------------- init.el -------------------------
> > (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)
> > ;(setq hkey-init nil)
> > (hyperbole-mode 1)
> > ------------------------- init.el -------------------------
> >
> > Execute Emacs as:
> >
> >   ./src/emacs -Q -l ~/tmp/init.el +181 ~/tmp/P1.java
> >
> > That always freezes Emacs (29 and master) even before it has a chance to
> > display P1.java.  The freeze happens in function
> > `c-get-fallback-scan-pos', where the while loop inf-loops, BUT:
> >
> > If you uncomment the line setting `hkey-init' to nil in init.el and
> > repeat: No freeze.
>
> I have tried to recreate the freezing (with 29.1 running docker) and I
> don't
> see the exact same behavior. For me P1.java is displayed and there us no
> freeze but when I try to go to top or bottom of file it freezes and I have
> to
> hit C-g. After that it seems to work. This is just an observation. There
> can
> be more things affected of course.
>
> I have tried both with the hyperbole stable and devel packages and get the
> same behavior.
>
> Note: I don't know what P1.java means here. I have picked a java file at
> random that I had on my machine that is large. Is P1.java a specific file
> that
> has been shared earlier?
>
> > Not sure how to continue here - since this is a GNU ELPA package, it can
> > be further handled on Emacs debbugs, no?  Mats, Bob?
>
> Hyperbole has its own tracker.
>
> https://debbugs.gnu.org/cgi/pkgreport.cgi?package=hyperbole
>
> %% Mats
>

[-- Attachment #2: Type: text/html, Size: 4709 bytes --]

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

* bug#61436: Emacs Freezing With Java Files
  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
                                       ` (2 more replies)
  0 siblings, 3 replies; 33+ messages in thread
From: Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-11 19:38 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Robert Weiner, Hank Greenburg, Mats Lidell, Eli Zaretskii, rswgnu,
	61436

Hi Alan,

could you please have a look as well?  This seems to be related to
cc-mode/java-mode.  New, complete reproducer at the very bottom of this
mail.

Thanks!

Hi Robert & Mats,

Robert Weiner <rsw@gnu.org> writes:

> Jens wrote:
>
>> That always freezes Emacs (29 and master) even before it has a chance to
>> display P1.java.  The freeze happens in function
>> `c-get-fallback-scan-pos', where the while loop inf-loops, BUT:
>>
>> If you uncomment the line setting `hkey-init' to nil in init.el and
>> repeat: No freeze.
>
> As you note above, the infinite loop is coming from a Lisp function in
> Emacs core, not from Hyperbole.  A Hyperbole setting may help you to
> see a state reached in that function that you otherwise would not, but
> it is not a Hyperbole bug; it is an unhandled state outside of
> Hyperbole.

Well, yes and no.  The next closest culprit seems to be this hook
addition from function `hui-select-initialize':

  ;; These hooks let you select C++ and Java methods and classes by
  ;; double-clicking on the first character of a definition or on its
  ;; opening or closing brace.  This is all necessary since some
  ;; programmers don't put their function braces in the first column.
  (var:add-and-run-hook
   'java-mode-hook
   (lambda ()
     (setq defun-prompt-regexp
	   "^[ \t]*\\(\\(\\(public\\|protected\\|private\\|const\\|abstract\\|synchronized\\|final\\|static\\|threadsafe\\|transient\\|native\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\)\\s-+\\)\\)?\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()\x7f=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+\\)?\\s-*")))

I (very generally) think that Emacs does not have to grok every regexp
in every context, but I leave that concrete case for Alan and/or others
to decide.

> On Wed, Oct 11, 2023 at 3:29 AM Mats Lidell <mats.lidell@lidells.se> wrote:
>
>  Thanks for the report.

Actually, not mine.  I'm just the messenger who did some root-cause
analysis.

>  Note: I don't know what P1.java means here. I have picked a java file
>  at random that I had on my machine that is large. Is P1.java a
>  specific file that has been shared earlier?

The OP has provided that, see below.

>  Hyperbole has its own tracker.
>
>  https://debbugs.gnu.org/cgi/pkgreport.cgi?package=hyperbole

Ok, thanks.  As soon as we know whose bug this is we could forward or
not.


Now for the next reproducer (Hyperbole no longer required, but still
present through its regexp :-):

- Save the following to ~/tmp/init.el:

------------------------- snip -------------------------
(add-hook
 'java-mode-hook
 (lambda ()
   (setq defun-prompt-regexp
	 "^[ \t]*\\(\\(\\(public\\|protected\\|private\\|const\\|abstract\\|synchronized\\|final\\|static\\|threadsafe\\|transient\\|native\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\)\\s-+\\)\\)?\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()\x7f=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+\\)?\\s-*")))
------------------------- snip -------------------------

- Save attachment P1.java from the initial message

  https://yhetil.org/emacs-bugs/ZPOcahP9yPJ-kLcgipM3-l0jatXJSQWKPfObrlOkIB3dagud85x2DGXGhPpQn1QNqNksVmPIRc1intyW_Cx1Z9ou2vBZ5QLDpLTi_VFVYyg=@protonmail.com/

  to ~/tmp/P1.java.

- Start Emacs as

  ./src/emacs -Q -l ~/tmp/init.el +181 ~/tmp/P1.java

That always freezes Emacs (29 and master) even before it has a chance to
display P1.java.  The freeze happens in function
`c-get-fallback-scan-pos', where the while loop inf-loops.





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

* bug#61436: Emacs Freezing With Java Files
  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
  2 siblings, 0 replies; 33+ messages in thread
From: Robert Weiner @ 2023-10-11 20:07 UTC (permalink / raw)
  To: Jens Schmidt
  Cc: Robert Weiner, Hank Greenburg, Mats Lidell, Alan Mackenzie,
	Eli Zaretskii, 61436

Those are some pretty old regexps in Hyperbole that we have not updated in many years.  Maybe we just need to cross-check them against what is currently in Emacs to resolve this.  I will have a look.  Thanks for tracing through this.

-- rsw

> On Oct 11, 2023, at 8:38 PM, Jens Schmidt <jschmidt4gnu@vodafonemail.de> wrote:
> 
> Hi Alan,
> 
> could you please have a look as well?  This seems to be related to
> cc-mode/java-mode.  New, complete reproducer at the very bottom of this
> mail.
> 
> Thanks!
> 
> Hi Robert & Mats,
> 
> Robert Weiner <rsw@gnu.org> writes:
> 
>> Jens wrote:
>> 
>>> That always freezes Emacs (29 and master) even before it has a chance to
>>> display P1.java.  The freeze happens in function
>>> `c-get-fallback-scan-pos', where the while loop inf-loops, BUT:
>>> 
>>> If you uncomment the line setting `hkey-init' to nil in init.el and
>>> repeat: No freeze.
>> 
>> As you note above, the infinite loop is coming from a Lisp function in
>> Emacs core, not from Hyperbole.  A Hyperbole setting may help you to
>> see a state reached in that function that you otherwise would not, but
>> it is not a Hyperbole bug; it is an unhandled state outside of
>> Hyperbole.
> 
> Well, yes and no.  The next closest culprit seems to be this hook
> addition from function `hui-select-initialize':
> 
>  ;; These hooks let you select C++ and Java methods and classes by
>  ;; double-clicking on the first character of a definition or on its
>  ;; opening or closing brace.  This is all necessary since some
>  ;; programmers don't put their function braces in the first column.
>  (var:add-and-run-hook
>   'java-mode-hook
>   (lambda ()
>     (setq defun-prompt-regexp
>       "^[ \t]*\\(\\(\\(public\\|protected\\|private\\|const\\|abstract\\|synchronized\\|final\\|static\\|threadsafe\\|transient\\|native\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\)\\s-+\\)\\)?\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()\x7f=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+\\)?\\s-*")))
> 
> I (very generally) think that Emacs does not have to grok every regexp
> in every context, but I leave that concrete case for Alan and/or others
> to decide.
> 
>> On Wed, Oct 11, 2023 at 3:29 AM Mats Lidell <mats.lidell@lidells.se> wrote:
>> 
>> Thanks for the report.
> 
> Actually, not mine.  I'm just the messenger who did some root-cause
> analysis.
> 
>> Note: I don't know what P1.java means here. I have picked a java file
>> at random that I had on my machine that is large. Is P1.java a
>> specific file that has been shared earlier?
> 
> The OP has provided that, see below.
> 
>> Hyperbole has its own tracker.
>> 
>> https://debbugs.gnu.org/cgi/pkgreport.cgi?package=hyperbole
> 
> Ok, thanks.  As soon as we know whose bug this is we could forward or
> not.
> 
> 
> Now for the next reproducer (Hyperbole no longer required, but still
> present through its regexp :-):
> 
> - Save the following to ~/tmp/init.el:
> 
> ------------------------- snip -------------------------
> (add-hook
> 'java-mode-hook
> (lambda ()
>   (setq defun-prompt-regexp
>     "^[ \t]*\\(\\(\\(public\\|protected\\|private\\|const\\|abstract\\|synchronized\\|final\\|static\\|threadsafe\\|transient\\|native\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\)\\s-+\\)\\)?\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()\x7f=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+\\)?\\s-*")))
> ------------------------- snip -------------------------
> 
> - Save attachment P1.java from the initial message
> 
>  https://yhetil.org/emacs-bugs/ZPOcahP9yPJ-kLcgipM3-l0jatXJSQWKPfObrlOkIB3dagud85x2DGXGhPpQn1QNqNksVmPIRc1intyW_Cx1Z9ou2vBZ5QLDpLTi_VFVYyg=@protonmail.com/
> 
>  to ~/tmp/P1.java.
> 
> - Start Emacs as
> 
>  ./src/emacs -Q -l ~/tmp/init.el +181 ~/tmp/P1.java
> 
> That always freezes Emacs (29 and master) even before it has a chance to
> display P1.java.  The freeze happens in function
> `c-get-fallback-scan-pos', where the while loop inf-loops.





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

* bug#61436: Emacs Freezing With Java Files
  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
  2 siblings, 0 replies; 33+ messages in thread
From: Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-11 21:43 UTC (permalink / raw)
  To: Jens Schmidt
  Cc: Robert Weiner, Hank Greenburg, Alan Mackenzie, Eli Zaretskii,
	rswgnu, 61436

Hi,

> Jens Schmidt writes:
> Now for the next reproducer (Hyperbole no longer required, but still
> present through its regexp :-):

I can confirm that I get a harder freeze this time using the submitted P1.java
file.  I now get the reported behavior of not even displaying the file.

I've tried at occasions, over the last years, to use Emacs for coding java in
my day job. It has always ended in some freeze that feels quite like this. I
bet it is this. Would be a fun irony if it is Hyperboles regexp that has
caused it, and it is about to be solved now when I'm not coding java! 🤣

Anyway, I will take a look too. With the clear description and easy to
reproduce it could be possible to solve! ;-) 

%% Mats





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

* bug#61436: Emacs Freezing With Java Files
  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
  2 siblings, 1 reply; 33+ messages in thread
From: Alan Mackenzie @ 2023-10-11 22:03 UTC (permalink / raw)
  To: Jens Schmidt
  Cc: Robert Weiner, Hank Greenburg, Mats Lidell, Eli Zaretskii, rswgnu,
	61436

Hello, Jens.

On Wed, Oct 11, 2023 at 21:38:26 +0200, Jens Schmidt wrote:
> Hi Alan,

> could you please have a look as well?  This seems to be related to
> cc-mode/java-mode.  New, complete reproducer at the very bottom of this
> mail.

> Thanks!

> Hi Robert & Mats,

> Robert Weiner <rsw@gnu.org> writes:

> > Jens wrote:

> >> That always freezes Emacs (29 and master) even before it has a chance to
> >> display P1.java.  The freeze happens in function
> >> `c-get-fallback-scan-pos', where the while loop inf-loops, BUT:

> >> If you uncomment the line setting `hkey-init' to nil in init.el and
> >> repeat: No freeze.

> > As you note above, the infinite loop is coming from a Lisp function in
> > Emacs core, not from Hyperbole.  A Hyperbole setting may help you to
> > see a state reached in that function that you otherwise would not, but
> > it is not a Hyperbole bug; it is an unhandled state outside of
> > Hyperbole.

> Well, yes and no.  The next closest culprit seems to be this hook
> addition from function `hui-select-initialize':

>   ;; These hooks let you select C++ and Java methods and classes by
>   ;; double-clicking on the first character of a definition or on its
>   ;; opening or closing brace.  This is all necessary since some
>   ;; programmers don't put their function braces in the first column.
>   (var:add-and-run-hook
>    'java-mode-hook
>    (lambda ()
>      (setq defun-prompt-regexp
> 	   "^[ \t]*\\(\\(\\(public\\|protected\\|private\\|const\\|abstract\\|synchronized\\|final\\|static\\|threadsafe\\|transient\\|native\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\)\\s-+\\)\\)?\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()\x7f=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+\\)?\\s-*")))

> I (very generally) think that Emacs does not have to grok every regexp
> in every context, but I leave that concrete case for Alan and/or others
> to decide.

I think that that regexp might be the source of the hang.  It is
ill-conditioned.  (I've elided all of the keywords between "public" and
"volatile" to try and make it more readable):

"^[ \t]*\\(\\(\\(public\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\))\\s-+\\)\\)? \\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()^?=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+\\)?\\s-*"

The first problem seems to be just after "volatile\\)\\s-+\\)*", where you've got:

[[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]
                         ^                ^

, in other words [...]*[...]+, where the ...s match largely the same
characters.  In the event of a failure to match, the Emacs regexp engine
will try every possible combination of these.  This isn't all that bad,
but in a string of N matching characters inside a global mismatch, it
will try out all N-1 ways of splitting up the string between those two
regexp fragments.  In fact, here, the [...]* is entirely redundant (as
well as being harmful) and could be removed.

Another problem is right near the end of the regexp where there is:

\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+

, or rewriting it in an easier to read fashion on several lines:

\\(                                            \\)+  
   \\(                         \\)[, \t\n\r\f]*
      [_$a-zA-Z][_$.a-zA-Z0-9]*
      1111111111111111111111111   2222222222222


.  Here, if you have a sequence of identifier characters, which are
inside a global mismatch, they can all be matched by 1.  However, they
can also be matched by 1, with any number (especially an infinite number)
of zero length strings matching 2.  In this case, the regexp engine will
try out all the ways of matching, an infinite number of them, before
giving up.  Here might be one of the places in the regexp which is
hanging.  It might well be that the second * in that expression should be
a +.

Earlier on in the regexp, I can see \\s-*\\)\\s-+, a possibly zero-length
sequence of space-syntax characters, followed by a non-empty sequence of
them.  I haven't analysed this in detail, but it smells like trouble.

It may well be that persevering with this regexp is a lost cause, and
you'd do better to construct a new regexp from scratch using more
structured methods (perhaps something similar to what's in cc-awk.el).
In fact the regexp looks horribly like one in the CC Mode manual which
was explicitly designated unsupported.  ;-(

Just as a matter of interest, I wrote a tool quite a few years ago to
diagnose and rewrite ill-conditioned regexps, but never got it to release
quality.  I tried out this tool on the regexp, but its output regexp hung
in Java Mode just as much as the original.  But this tool did help me
spot some of the solecisms which I analysed above.


> > On Wed, Oct 11, 2023 at 3:29 AM Mats Lidell <mats.lidell@lidells.se> wrote:
> >
> >  Thanks for the report.

> Actually, not mine.  I'm just the messenger who did some root-cause
> analysis.

> >  Note: I don't know what P1.java means here. I have picked a java file
> >  at random that I had on my machine that is large. Is P1.java a
> >  specific file that has been shared earlier?

> The OP has provided that, see below.

> >  Hyperbole has its own tracker.
> >
> >  https://debbugs.gnu.org/cgi/pkgreport.cgi?package=hyperbole

> Ok, thanks.  As soon as we know whose bug this is we could forward or
> not.


> Now for the next reproducer (Hyperbole no longer required, but still
> present through its regexp :-):

> - Save the following to ~/tmp/init.el:

> ------------------------- snip -------------------------
> (add-hook
>  'java-mode-hook
>  (lambda ()
>    (setq defun-prompt-regexp
> 	 "^[ \t]*\\(\\(\\(public\\|protected\\|private\\|const\\|abstract\\|synchronized\\|final\\|static\\|threadsafe\\|transient\\|native\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\)\\s-+\\)\\)?\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()\x7f=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+\\)?\\s-*")))
> ------------------------- snip -------------------------

> - Save attachment P1.java from the initial message

>   https://yhetil.org/emacs-bugs/ZPOcahP9yPJ-kLcgipM3-l0jatXJSQWKPfObrlOkIB3dagud85x2DGXGhPpQn1QNqNksVmPIRc1intyW_Cx1Z9ou2vBZ5QLDpLTi_VFVYyg=@protonmail.com/

>   to ~/tmp/P1.java.

> - Start Emacs as

>   ./src/emacs -Q -l ~/tmp/init.el +181 ~/tmp/P1.java

> That always freezes Emacs (29 and master) even before it has a chance to
> display P1.java.  The freeze happens in function
> `c-get-fallback-scan-pos', where the while loop inf-loops.

c-get-fallback-scan-pos tries to move to the beginning of a function.
This probably involves defun-prompt-regexp when it is non-nil.  :-(

-- 
Alan Mackenzie (Nuremberg, Germany).





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-12 19:58 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Robert Weiner, Hank Greenburg, Mats Lidell, Eli Zaretskii, rswgnu,
	61436

Hi Alan,

Alan Mackenzie <acm@muc.de> writes:

> It may well be that persevering with this regexp is a lost cause, and
> you'd do better to construct a new regexp from scratch using more
> structured methods (perhaps something similar to what's in cc-awk.el).
> In fact the regexp looks horribly like one in the CC Mode manual which
> was explicitly designated unsupported.  ;-(

and thanks for your analysis.  I felt as well that this regexp looks,
well, funny, but what intrigues me is that it cannot (only) be the
complexity and ill-conditioned-ness of that regexp that lets Emacs
freeze.

>> That always freezes Emacs (29 and master) even before it has a chance to
>> display P1.java.  The freeze happens in function
>> `c-get-fallback-scan-pos', where the while loop inf-loops.
>
> c-get-fallback-scan-pos tries to move to the beginning of a function.
> This probably involves defun-prompt-regexp when it is non-nil.  :-(

Otherwise we would see hangs or exponential behavior (?) somewhere in
the Emacs regexp machinerie, but they take place in that while loop.  So
I guess that there must be some other, additional quality that this
regexp fulfills.  Like: "matches the empty string" (which it does not,
as far as I can tell) or: "must only match before curlies" or whatnot.

Unfortunately, the doc string/info doc of `defun-prompt-regexp´ provides
only exactly that latter criterion:

  That is to say, a defun begins on a line that starts with a match for
  this regular expression, followed by a character with open-parenthesis
  syntax.

I guess that only pruning that regexp until things start unfreezing
could give an answer here.  Or more tracing to see how point moves in
`c-get-fallback-scan-pos'.  But I need some tracing break here ...


... or so I thought, I just couldn't resist:

I expanded and instrumented that function from emacs-29 as follows,
(hopefully) not changing any of its logic:

------------------------- snip -------------------------
(defun c-get-fallback-scan-pos (here)
  ;; Return a start position for building `c-state-cache' from scratch.  This
  ;; will be at the top level, 2 defuns back.  Return nil if we don't find
  ;; these defun starts a reasonable way back.
  (message "c-get-fallback-scan-pos")
  (save-excursion
    (save-restriction
      (when (> here (* 10 c-state-cache-too-far))
	(narrow-to-region (- here (* 10 c-state-cache-too-far)) here))
      ;; Go back 2 bods, but ignore any bogus positions returned by
      ;; beginning-of-defun (i.e. open paren in column zero).
      (goto-char here)
      (let ((cnt 2))
	(message "beginning-of-defun-loop-00: %d %d" cnt (point))
	(while (not (or (bobp) (zerop cnt)))
	  (message "beginning-of-defun-loop-01: %d" (point))
	  (let (beginning-of-defun-function end-of-defun-function)
	    (beginning-of-defun))
	  (and defun-prompt-regexp
	       (looking-at defun-prompt-regexp)
	       (message "beginning-of-defun-loop-02: %d" (point))
	       (goto-char (match-end 0)))
	  (message "beginning-of-defun-loop-03: %d" (point))
	  (if (eq (char-after) ?\{)
	      (setq cnt (1- cnt)))))
      (and (not (bobp))
	   (point)))))
------------------------- snip -------------------------

That results in the message triple

------------------------- snip -------------------------
beginning-of-defun-loop-01: 5879
beginning-of-defun-loop-02: 5801
beginning-of-defun-loop-03: 5879
beginning-of-defun-loop-01: 5879
beginning-of-defun-loop-02: 5801
beginning-of-defun-loop-03: 5879
...
------------------------- snip -------------------------

inf-looping.  These points are (|: 5801, ^: 5879) here in P1.java:

------------------------- snip -------------------------
178    } catch (Exception e) {
179|      error("symTable.addDecl", "unexpected error with a single HashMap " + e)^;
180    }
181
------------------------- snip -------------------------

So the catch-block just before line 181 is recognized as a potential BOD
(previous trailing open curly?).  But then `defun-prompt-regexp' matches
the function call in the catch-block as defun prompt regexp (which it
better should not?), taking point back to where, on next BOD search, the
exact previous BOD is found again.

So probably there are really two issues here:

1. The `defun-prompt-regexp' used by Hyperbole, which matches too
   broadly, and

2. function `c-get-fallback-scan-pos', which could try harder to avoid
   inf-loops when such things happen.

But that's where I *really* stop here :-)





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

* bug#61436: Emacs Freezing With Java Files
  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
                                             ` (2 more replies)
  0 siblings, 3 replies; 33+ messages in thread
From: Alan Mackenzie @ 2023-10-13 12:41 UTC (permalink / raw)
  To: Jens Schmidt
  Cc: Robert Weiner, Hank Greenburg, Mats Lidell, Eli Zaretskii, rswgnu,
	61436

[-- Attachment #1: Type: text/plain, Size: 5280 bytes --]

Hello, Jens.

On Thu, Oct 12, 2023 at 21:58:06 +0200, Jens Schmidt wrote:
> Hi Alan,

> Alan Mackenzie <acm@muc.de> writes:

[ .... ]

> >> That always freezes Emacs (29 and master) even before it has a chance to
> >> display P1.java.  The freeze happens in function
> >> `c-get-fallback-scan-pos', where the while loop inf-loops.

Yes.

> > c-get-fallback-scan-pos tries to move to the beginning of a function.
> > This probably involves defun-prompt-regexp when it is non-nil.  :-(

> Otherwise we would see hangs or exponential behavior (?) somewhere in
> the Emacs regexp machinerie, but they take place in that while loop.  So
> I guess that there must be some other, additional quality that this
> regexp fulfills.  Like: "matches the empty string" (which it does not,
> as far as I can tell) or: "must only match before curlies" or whatnot.

> Unfortunately, the doc string/info doc of `defun-prompt-regexp´ provides
> only exactly that latter criterion:

>   That is to say, a defun begins on a line that starts with a match for
>   this regular expression, followed by a character with open-parenthesis
>   syntax.

> I guess that only pruning that regexp until things start unfreezing
> could give an answer here.  Or more tracing to see how point moves in
> `c-get-fallback-scan-pos'.  But I need some tracing break here ...


> ... or so I thought, I just couldn't resist:

> I expanded and instrumented that function from emacs-29 as follows,
> (hopefully) not changing any of its logic:

> ------------------------- snip -------------------------
> (defun c-get-fallback-scan-pos (here)
>   ;; Return a start position for building `c-state-cache' from scratch.  This
>   ;; will be at the top level, 2 defuns back.  Return nil if we don't find
>   ;; these defun starts a reasonable way back.
>   (message "c-get-fallback-scan-pos")
>   (save-excursion
>     (save-restriction
>       (when (> here (* 10 c-state-cache-too-far))
> 	(narrow-to-region (- here (* 10 c-state-cache-too-far)) here))
>       ;; Go back 2 bods, but ignore any bogus positions returned by
>       ;; beginning-of-defun (i.e. open paren in column zero).
>       (goto-char here)
>       (let ((cnt 2))
> 	(message "beginning-of-defun-loop-00: %d %d" cnt (point))
> 	(while (not (or (bobp) (zerop cnt)))
> 	  (message "beginning-of-defun-loop-01: %d" (point))
> 	  (let (beginning-of-defun-function end-of-defun-function)
> 	    (beginning-of-defun))
> 	  (and defun-prompt-regexp
> 	       (looking-at defun-prompt-regexp)
> 	       (message "beginning-of-defun-loop-02: %d" (point))
> 	       (goto-char (match-end 0)))
> 	  (message "beginning-of-defun-loop-03: %d" (point))
> 	  (if (eq (char-after) ?\{)
> 	      (setq cnt (1- cnt)))))
>       (and (not (bobp))
> 	   (point)))))
> ------------------------- snip -------------------------

> That results in the message triple

> ------------------------- snip -------------------------
> beginning-of-defun-loop-01: 5879
> beginning-of-defun-loop-02: 5801
> beginning-of-defun-loop-03: 5879
> beginning-of-defun-loop-01: 5879
> beginning-of-defun-loop-02: 5801
> beginning-of-defun-loop-03: 5879
> ...
> ------------------------- snip -------------------------

> inf-looping.  These points are (|: 5801, ^: 5879) here in P1.java:

> ------------------------- snip -------------------------
> 178    } catch (Exception e) {
> 179|      error("symTable.addDecl", "unexpected error with a single HashMap " + e)^;
> 180    }
> 181
> ------------------------- snip -------------------------

> So the catch-block just before line 181 is recognized as a potential BOD
> (previous trailing open curly?).  But then `defun-prompt-regexp' matches
> the function call in the catch-block as defun prompt regexp (which it
> better should not?), taking point back to where, on next BOD search, the
> exact previous BOD is found again.

> So probably there are really two issues here:

> 1. The `defun-prompt-regexp' used by Hyperbole, which matches too
>    broadly, and

> 2. function `c-get-fallback-scan-pos', which could try harder to avoid
>    inf-loops when such things happen.

> But that's where I *really* stop here :-)

You've diagnosed the bug completely.  Thanks!  The hang was caused
entirely by the loop in c-get-fallback-scan-pos, not the deficiencies in
that long regexp.

defun-prompt-regexp, when appended with a \\s( (as is done in
beginning-of-defun-raw) matches the "      error(" on L179 of P1.java.
The bare defun-prompt-regexp (as used in CC Mode) matches the entire
line except the terminating ;.  This regexp could do with some
amendment, but it is not the main cause of the bug.

To solve the bug, I'm amending the macro c-beginning-of-defun-1 so that
it only stops at a debug-prompt-regexp position when it also found a {.
Otherwise it will keep looping until it finds a better position or BOB.

Would all concerned please apply the attached patch to the Emacs master
branch, directory lisp/progmodes.  Then please byte compile CC Mode in
full (a macro has been changed), and try the result on your real Java
code.  (If anybody wants any help applying the patch or byte compiling,
feel free to send me private mail.)  Then please confirm that the bug is
indeed fixed.  Thanks!

-- 
Alan Mackenzie (Nuremberg, Germany).


[-- Attachment #2: diff.20231013.diff --]
[-- Type: text/plain, Size: 3677 bytes --]

diff -r b680bbba3141 cc-defs.el
--- a/cc-defs.el	Fri Sep 29 11:15:58 2023 +0000
+++ b/cc-defs.el	Fri Oct 13 12:23:11 2023 +0000
@@ -944,7 +944,8 @@
      (when dest (goto-char dest) t)))
 \f
 (defmacro c-beginning-of-defun-1 ()
-  ;; Wrapper around beginning-of-defun.
+  ;; Wrapper around beginning-of-defun.  Note that the return value from this
+  ;; macro has no significance.
   ;;
   ;; NOTE: This function should contain the only explicit use of
   ;; beginning-of-defun in CC Mode.  Eventually something better than
@@ -957,44 +958,49 @@
   ;; `c-parse-state'.
 
   `(progn
-     (if (and ,(fboundp 'buffer-syntactic-context-depth)
-	      c-enable-xemacs-performance-kludge-p)
-	 ,(when (fboundp 'buffer-syntactic-context-depth)
-	    ;; XEmacs only.  This can improve the performance of
-	    ;; c-parse-state to between 3 and 60 times faster when
-	    ;; braces are hung.  It can also degrade performance by
-	    ;; about as much when braces are not hung.
-	    '(let (beginning-of-defun-function end-of-defun-function
-					       pos)
-	       (while (not pos)
-		 (save-restriction
-		   (widen)
-		   (setq pos (c-safe-scan-lists
-			      (point) -1 (buffer-syntactic-context-depth))))
-		 (cond
-		  ((bobp) (setq pos (point-min)))
-		  ((not pos)
-		   (let ((distance (skip-chars-backward "^{")))
-		     ;; unbalanced parenthesis, while invalid C code,
-		     ;; shouldn't cause an infloop!  See unbal.c
-		     (when (zerop distance)
-		       ;; Punt!
-		       (beginning-of-defun)
-		       (setq pos (point)))))
-		  ((= pos 0))
-		  ((not (eq (char-after pos) ?{))
-		   (goto-char pos)
-		   (setq pos nil))
-		  ))
-	       (goto-char pos)))
-       ;; Emacs, which doesn't have buffer-syntactic-context-depth
-       (let (beginning-of-defun-function end-of-defun-function)
-	 (beginning-of-defun)))
-     ;; if defun-prompt-regexp is non-nil, b-o-d won't leave us at the
-     ;; open brace.
-     (and defun-prompt-regexp
-	  (looking-at defun-prompt-regexp)
-	  (goto-char (match-end 0)))))
+     (while
+	 (progn
+	   (if (and ,(fboundp 'buffer-syntactic-context-depth)
+		    c-enable-xemacs-performance-kludge-p)
+	       ,(when (fboundp 'buffer-syntactic-context-depth)
+		  ;; XEmacs only.  This can improve the performance of
+		  ;; c-parse-state to between 3 and 60 times faster when
+		  ;; braces are hung.  It can also degrade performance by
+		  ;; about as much when braces are not hung.
+		  '(let (beginning-of-defun-function end-of-defun-function
+						     pos)
+		     (while (not pos)
+		       (save-restriction
+			 (widen)
+			 (setq pos (c-safe-scan-lists
+				    (point) -1 (buffer-syntactic-context-depth))))
+		       (cond
+			((bobp) (setq pos (point-min)))
+			((not pos)
+			 (let ((distance (skip-chars-backward "^{")))
+			   ;; unbalanced parenthesis, while invalid C code,
+			   ;; shouldn't cause an infloop!  See unbal.c
+			   (when (zerop distance)
+			     ;; Punt!
+			     (beginning-of-defun)
+			     (setq pos (point)))))
+			((= pos 0))
+			((not (eq (char-after pos) ?{))
+			 (goto-char pos)
+			 (setq pos nil))
+			))
+		     (goto-char pos)))
+	     ;; Emacs, which doesn't have buffer-syntactic-context-depth
+	     (let (beginning-of-defun-function end-of-defun-function)
+	       (beginning-of-defun)))
+	   (and (not (bobp))
+		;; if defun-prompt-regexp is non-nil, b-o-d won't leave us at
+		;; the open brace.
+		defun-prompt-regexp
+		(looking-at (concat defun-prompt-regexp "\\s("))
+		(or (not (eq (char-before (match-end 0)) ?{))
+		    (progn (goto-char (1- (match-end 0)))
+			   nil)))))))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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

* bug#61436: Emacs Freezing With Java Files
  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
  2024-04-19  2:58                           ` Robert Weiner
  2 siblings, 0 replies; 33+ messages in thread
From: Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-13 18:02 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Robert Weiner, Hank Greenburg, Eli Zaretskii, rswgnu,
	Jens Schmidt, 61436

Hi Alan,

> Alan Mackenzie writes:
> Would all concerned please apply the attached patch to the Emacs master
> branch, directory lisp/progmodes.  Then please byte compile CC Mode in
> full (a macro has been changed), and try the result on your real Java
> code.  (If anybody wants any help applying the patch or byte compiling,
> feel free to send me private mail.)  Then please confirm that the bug is
> indeed fixed.  Thanks!

I have verified that there is no freeze with the patch applied for the test
case with the P1.java file. Latest master as of today with native byte
compilation.  (Commit = baf778c7caa) Without the patch the freeze is there. So
is looking good. :-)

Yours
-- 
%% Mats





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

* bug#61436: Emacs Freezing With Java Files
  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
  2024-04-19  2:58                           ` Robert Weiner
  2 siblings, 1 reply; 33+ messages in thread
From: Jens Schmidt via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-13 20:42 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Robert Weiner, Hank Greenburg, Mats Lidell, Eli Zaretskii, rswgnu,
	61436

Hi Alan,

Alan Mackenzie <acm@muc.de> writes:

> To solve the bug, I'm amending the macro c-beginning-of-defun-1 so that
> it only stops at a debug-prompt-regexp position when it also found a {.
> Otherwise it will keep looping until it finds a better position or BOB.

Thanks.

> Then please confirm that the bug is
> indeed fixed.

For the fun of it I tried Hank's initial testcase as well, which is a
bit less straight-forward to set up.  The freezes are indeed gone with
your patch.  But I noticed that which-function-mode, when rapidly moving
through the file, cannot always determine the current function name,
then displaying "[n/a]" in the mode line.

And indeed, when executing the simplified test case

  ./src/emacs -Q -l ~/tmp/init.el +181 ~/tmp/P1.java

and then immediately hitting C-M-a, point jumps to the beginning of the
preceeding catch clause (point=5779 of 18142) instead of BOD.

This behavior is again tied to the `defun-prompt-regexp' used by
Hyperbole - without that regexp C-M-a jumps to the real BOD.





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Alan Mackenzie @ 2023-10-14 19:41 UTC (permalink / raw)
  To: Jens Schmidt, Mats Lidell
  Cc: Robert Weiner, Hank Greenburg, 61436-done, acm, Eli Zaretskii,
	rswgnu

Hello, Jens and Mats.

On Fri, Oct 13, 2023 at 22:42:04 +0200, Jens Schmidt wrote:
> Hi Alan,

> Alan Mackenzie <acm@muc.de> writes:

> > To solve the bug, I'm amending the macro c-beginning-of-defun-1 so that
> > it only stops at a debug-prompt-regexp position when it also found a {.
> > Otherwise it will keep looping until it finds a better position or BOB.

> Thanks.

> > Then please confirm that the bug is indeed fixed.

> For the fun of it I tried Hank's initial testcase as well, which is a
> bit less straight-forward to set up.  The freezes are indeed gone with
> your patch.

Thanks for the testing.  Seeing as how both of you confirm the original
bug is fixed with the patch, I'm closing it with this post.

> But I noticed that which-function-mode, when rapidly moving through
> the file, cannot always determine the current function name, then
> displaying "[n/a]" in the mode line.

> And indeed, when executing the simplified test case

>   ./src/emacs -Q -l ~/tmp/init.el +181 ~/tmp/P1.java

> and then immediately hitting C-M-a, point jumps to the beginning of the
> preceeding catch clause (point=5779 of 18142) instead of BOD.

I can't reproduce this, even when setting defun-prompt-regexp to the
original large regexp from hui-select.el.

> This behavior is again tied to the `defun-prompt-regexp' used by
> Hyperbole - without that regexp C-M-a jumps to the real BOD.

Mats, I'm willing to work on that regular expression, and also the one
for C++.  As I mentioned earlier, I've got some tools which work on
regexps, in particular pp-regexp, which prints a regexp more readably on
several lines, and fix-re, which rewrites a regexp when it is
ill-conditioned in certain ways.

I foresee reverse engineering the regexps into more readable forms built
up by concatenating basic blocks.  For example for the java regexp I
would define

    (defconst id "[a-zA-Z][][_$.a-zA-Z0-9]*")

, and use this id in a largish concat form.

I'm also willing to share pp-regexp and fix-re with you(r team), if that
might help, on the understanding that neither is of release quality.

-- 
Alan Mackenzie (Nuremberg, Germany).





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

* bug#61436: Emacs Freezing With Java Files
  2023-10-14 19:41                             ` Alan Mackenzie
@ 2023-10-15 10:20                               ` Robert Weiner
  2023-10-16 14:05                                 ` Alan Mackenzie
  0 siblings, 1 reply; 33+ messages in thread
From: Robert Weiner @ 2023-10-15 10:20 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Robert Weiner, Hank Greenburg, Mats Lidell, 61436-done,
	Eli Zaretskii, Jens Schmidt

Hi Alan:

Would be great if you can improve those two regexps.  The only
requirement is that they be able to recognize all defuns in the two
languages as best a regexp can, so that the whole defun can be
selected based on finding the opening brace regardless of coding
style.

Thanks.

-- Bob

> On Oct 14, 2023, at 8:41 PM, Alan Mackenzie <acm@muc.de> wrote:
>
> Hello, Jens and Mats.

>
>> On Fri, Oct 13, 2023 at 22:42:04 +0200, Jens Schmidt wrote:
>> Hi Alan,
>
>> Alan Mackenzie <acm@muc.de> writes:
>
>>> To solve the bug, I'm amending the macro c-beginning-of-defun-1 so that
>>> it only stops at a debug-prompt-regexp position when it also found a {.
>>> Otherwise it will keep looping until it finds a better position or BOB.
>
>> Thanks.
>
>>> Then please confirm that the bug is indeed fixed.
>
>> For the fun of it I tried Hank's initial testcase as well, which is a
>> bit less straight-forward to set up.  The freezes are indeed gone with
>> your patch.
>
> Thanks for the testing.  Seeing as how both of you confirm the original
> bug is fixed with the patch, I'm closing it with this post.
>
>> But I noticed that which-function-mode, when rapidly moving through
>> the file, cannot always determine the current function name, then
>> displaying "[n/a]" in the mode line.
>
>> And indeed, when executing the simplified test case
>
>>  ./src/emacs -Q -l ~/tmp/init.el +181 ~/tmp/P1.java
>
>> and then immediately hitting C-M-a, point jumps to the beginning of the
>> preceeding catch clause (point=5779 of 18142) instead of BOD.
>
> I can't reproduce this, even when setting defun-prompt-regexp to the
> original large regexp from hui-select.el.
>
>> This behavior is again tied to the `defun-prompt-regexp' used by
>> Hyperbole - without that regexp C-M-a jumps to the real BOD.
>
> Mats, I'm willing to work on that regular expression, and also the one
> for C++.  As I mentioned earlier, I've got some tools which work on
> regexps, in particular pp-regexp, which prints a regexp more readably on
> several lines, and fix-re, which rewrites a regexp when it is
> ill-conditioned in certain ways.
>
> I foresee reverse engineering the regexps into more readable forms built
> up by concatenating basic blocks.  For example for the java regexp I
> would define
>
>    (defconst id "[a-zA-Z][][_$.a-zA-Z0-9]*")
>
> , and use this id in a largish concat form.
>
> I'm also willing to share pp-regexp and fix-re with you(r team), if that
> might help, on the understanding that neither is of release quality.
>
> --
> Alan Mackenzie (Nuremberg, Germany).





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 2 replies; 33+ messages in thread
From: Alan Mackenzie @ 2023-10-16 14:05 UTC (permalink / raw)
  To: Robert Weiner
  Cc: Robert Weiner, Hank Greenburg, Mats Lidell, 61436-done, acm,
	Eli Zaretskii, Jens Schmidt

Hello, Bob.

On Sun, Oct 15, 2023 at 06:20:15 -0400, Robert Weiner wrote:
> Hi Alan:

> Would be great if you can improve those two regexps.  The only
> requirement is that they be able to recognize all defuns in the two
> languages as best a regexp can, so that the whole defun can be
> selected based on finding the opening brace regardless of coding
> style.

So far, I've only looked at the Java regexp.  It had some serious
deficiencies, notably:
(i) It used "\\s-" (space syntax) a lot.  This fails to mach \n, which in
Java mode has comment-end syntax.
(ii) The bit for the parenthesis expression was in an optional part of
the regexp with the result that it would match "almost anything" rather
than a defun start.

In the following regexp these faults are fixed.  Additionally, I've
included more modifiers (things like private, volatile) which Java seems
to have gathered over the years.  I've also attempted to match generic
functions.  I don't know how well this will work out.

Here's the regexp.  Would people please try it out and let me know how
well it works.  

(defconst java-defun-prompt-regexp
  (let ((space* "[ \t\n\r\f]*")
        (space+ "[ \t\n\r\f]+")
        (modifier*
         (concat "\\(?:"
                 (regexp-opt '("abstract" "const" "default" "final" "native"
                               "private" "protected" "public" "static"
                               "strictfp" "synchronized" "threadsafe"
                               "transient" "volatile")
                             'words)    ; Compatible with XEmacs
                 space+ "\\)*"))
        (ids-with-dots "[_$a-zA-Z][_$.a-zA-Z0-9]*")
        (ids-with-dot-\[\] "[[_$a-zA-Z][][_$.a-zA-Z0-9]*")
        (paren-exp "([^);{}]*)")
        (generic-exp "<[^(){};]*>"))
    (concat "^[ \t]*"
            modifier*
            "\\(?:" generic-exp space* "\\)?"
            ids-with-dot-\[\] space+                ; first part of type
            "\\(?:" ids-with-dot-\[\] space+ "\\)?" ; optional second part of type.
            "\\(?:[_a-zA-Z][^][ \t:;.,{}()=<>]*"    ; defun name
                "\\|" ids-with-dot*
            "\\)" space*
            paren-exp
            "\\(?:" space* "]\\)*"      ; What's this for?
            "\\(?:" space* "\\<throws\\>" space* ids-with-dot-\[\]s*
                  "\\(?:," space* ids-with-dot-\[\]s* "\\)*"
            "\\)?"
            space*)))

> Thanks.

> -- Bob

> > On Oct 14, 2023, at 8:41 PM, Alan Mackenzie <acm@muc.de> wrote:

[ .... ]

> > Mats, I'm willing to work on that regular expression, and also the one
> > for C++.  As I mentioned earlier, I've got some tools which work on
> > regexps, in particular pp-regexp, which prints a regexp more readably on
> > several lines, and fix-re, which rewrites a regexp when it is
> > ill-conditioned in certain ways.

> > I foresee reverse engineering the regexps into more readable forms built
> > up by concatenating basic blocks.  For example for the java regexp I
> > would define

> >    (defconst id "[a-zA-Z][][_$.a-zA-Z0-9]*")

> > , and use this id in a largish concat form.

> > I'm also willing to share pp-regexp and fix-re with you(r team), if that
> > might help, on the understanding that neither is of release quality.

-- 
Alan Mackenzie (Nuremberg, Germany).





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

* bug#61436: Emacs Freezing With Java Files
  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
  1 sibling, 0 replies; 33+ messages in thread
From: Robert Weiner @ 2023-10-16 19:10 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Robert Weiner, Hank Greenburg, Mats Lidell, 61436-done,
	Eli Zaretskii, Jens Schmidt

Nice job, Alan.  Thanks, look forward to trying it out.

-- Bob

> On Oct 16, 2023, at 3:05 PM, Alan Mackenzie <acm@muc.de> wrote:
> 
> Hello, Bob.
> 
>> On Sun, Oct 15, 2023 at 06:20:15 -0400, Robert Weiner wrote:
>> Hi Alan:
> 
>> Would be great if you can improve those two regexps.  The only
>> requirement is that they be able to recognize all defuns in the two
>> languages as best a regexp can, so that the whole defun can be
>> selected based on finding the opening brace regardless of coding
>> style.
> 
> So far, I've only looked at the Java regexp.  It had some serious
> deficiencies, notably:
> (i) It used "\\s-" (space syntax) a lot.  This fails to mach \n, which in
> Java mode has comment-end syntax.
> (ii) The bit for the parenthesis expression was in an optional part of
> the regexp with the result that it would match "almost anything" rather
> than a defun start.
> 
> In the following regexp these faults are fixed.  Additionally, I've
> included more modifiers (things like private, volatile) which Java seems
> to have gathered over the years.  I've also attempted to match generic
> functions.  I don't know how well this will work out.
> 
> Here's the regexp.  Would people please try it out and let me know how
> well it works.  
> 
> (defconst java-defun-prompt-regexp
>  (let ((space* "[ \t\n\r\f]*")
>        (space+ "[ \t\n\r\f]+")
>        (modifier*
>         (concat "\\(?:"
>                 (regexp-opt '("abstract" "const" "default" "final" "native"
>                               "private" "protected" "public" "static"
>                               "strictfp" "synchronized" "threadsafe"
>                               "transient" "volatile")
>                             'words)    ; Compatible with XEmacs
>                 space+ "\\)*"))
>        (ids-with-dots "[_$a-zA-Z][_$.a-zA-Z0-9]*")
>        (ids-with-dot-\[\] "[[_$a-zA-Z][][_$.a-zA-Z0-9]*")
>        (paren-exp "([^);{}]*)")
>        (generic-exp "<[^(){};]*>"))
>    (concat "^[ \t]*"
>            modifier*
>            "\\(?:" generic-exp space* "\\)?"
>            ids-with-dot-\[\] space+                ; first part of type
>            "\\(?:" ids-with-dot-\[\] space+ "\\)?" ; optional second part of type.
>            "\\(?:[_a-zA-Z][^][ \t:;.,{}()=<>]*"    ; defun name
>                "\\|" ids-with-dot*
>            "\\)" space*
>            paren-exp
>            "\\(?:" space* "]\\)*"      ; What's this for?
>            "\\(?:" space* "\\<throws\\>" space* ids-with-dot-\[\]s*
>                  "\\(?:," space* ids-with-dot-\[\]s* "\\)*"
>            "\\)?"
>            space*)))
> 
>> Thanks.
> 
>> -- Bob
> 
>>> On Oct 14, 2023, at 8:41 PM, Alan Mackenzie <acm@muc.de> wrote:
> 
> [ .... ]
> 
>>> Mats, I'm willing to work on that regular expression, and also the one
>>> for C++.  As I mentioned earlier, I've got some tools which work on
>>> regexps, in particular pp-regexp, which prints a regexp more readably on
>>> several lines, and fix-re, which rewrites a regexp when it is
>>> ill-conditioned in certain ways.
> 
>>> I foresee reverse engineering the regexps into more readable forms built
>>> up by concatenating basic blocks.  For example for the java regexp I
>>> would define
> 
>>>   (defconst id "[a-zA-Z][][_$.a-zA-Z0-9]*")
> 
>>> , and use this id in a largish concat form.
> 
>>> I'm also willing to share pp-regexp and fix-re with you(r team), if that
>>> might help, on the understanding that neither is of release quality.
> 
> -- 
> Alan Mackenzie (Nuremberg, Germany).





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

* bug#61436: Emacs Freezing With Java Files
  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
  1 sibling, 1 reply; 33+ messages in thread
From: Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-21 22:14 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Robert Weiner, Hank Greenburg, 61436-done, Eli Zaretskii,
	Robert Weiner, Jens Schmidt

Hi Alan,

Sorry for coming back late to this issue but today I tried to use the
suggested regexp and got into some problems doing that.

> Alan Mackenzie writes:
> Here's the regexp.  Would people please try it out and let me know how
> well it works.  
>
> (defconst java-defun-prompt-regexp
>   (let ((space* "[ \t\n\r\f]*")
>         (space+ "[ \t\n\r\f]+")
>         (modifier*
>          (concat "\\(?:"
>                  (regexp-opt '("abstract" "const" "default" "final" "native"
>                                "private" "protected" "public" "static"
>                                "strictfp" "synchronized" "threadsafe"
>                                "transient" "volatile")
>                              'words)    ; Compatible with XEmacs
>                  space+ "\\)*"))
>         (ids-with-dots "[_$a-zA-Z][_$.a-zA-Z0-9]*")
>         (ids-with-dot-\[\] "[[_$a-zA-Z][][_$.a-zA-Z0-9]*")
>         (paren-exp "([^);{}]*)")
>         (generic-exp "<[^(){};]*>"))
>     (concat "^[ \t]*"
>             modifier*
>             "\\(?:" generic-exp space* "\\)?"
>             ids-with-dot-\[\] space+                ; first part of type
>             "\\(?:" ids-with-dot-\[\] space+ "\\)?" ; optional second part of type.
>             "\\(?:[_a-zA-Z][^][ \t:;.,{}()=<>]*"    ; defun name
>                 "\\|" ids-with-dot*
>             "\\)" space*
>             paren-exp
>             "\\(?:" space* "]\\)*"      ; What's this for?
>             "\\(?:" space* "\\<throws\\>" space* ids-with-dot-\[\]s*
>                   "\\(?:," space* ids-with-dot-\[\]s* "\\)*"
>             "\\)?"
>             space*)))

Can there be some typos in there or missing lines? I get a compiler warning
for space+ being used in the let, should it be a let*? ids-with-dots is
reported as not used. Can it be meant to be ids-with-dot*?
ids-with-dot-\[\]s* is undefined!?

Yours
-- 
%% Mats





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

* bug#61436: Emacs Freezing With Java Files
  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
  0 siblings, 1 reply; 33+ messages in thread
From: Alan Mackenzie @ 2023-10-22 14:15 UTC (permalink / raw)
  To: Mats Lidell
  Cc: Robert Weiner, Hank Greenburg, 61436-done, acm, Eli Zaretskii,
	Robert Weiner, Jens Schmidt

Hello, Mats.

On Sun, Oct 22, 2023 at 00:14:43 +0200, Mats Lidell wrote:
> Hi Alan,

> Sorry for coming back late to this issue but today I tried to use the
> suggested regexp and got into some problems doing that.

Sorry about that.

> > Alan Mackenzie writes:
> > Here's the regexp.  Would people please try it out and let me know how
> > well it works.  
> >
> > (defconst java-defun-prompt-regexp
> >   (let ((space* "[ \t\n\r\f]*")
> >         (space+ "[ \t\n\r\f]+")
> >         (modifier*
> >          (concat "\\(?:"
> >                  (regexp-opt '("abstract" "const" "default" "final" "native"
> >                                "private" "protected" "public" "static"
> >                                "strictfp" "synchronized" "threadsafe"
> >                                "transient" "volatile")
> >                              'words)    ; Compatible with XEmacs
> >                  space+ "\\)*"))
> >         (ids-with-dots "[_$a-zA-Z][_$.a-zA-Z0-9]*")
> >         (ids-with-dot-\[\] "[[_$a-zA-Z][][_$.a-zA-Z0-9]*")
> >         (paren-exp "([^);{}]*)")
> >         (generic-exp "<[^(){};]*>"))
> >     (concat "^[ \t]*"
> >             modifier*
> >             "\\(?:" generic-exp space* "\\)?"
> >             ids-with-dot-\[\] space+                ; first part of type
> >             "\\(?:" ids-with-dot-\[\] space+ "\\)?" ; optional second part of type.
> >             "\\(?:[_a-zA-Z][^][ \t:;.,{}()=<>]*"    ; defun name
> >                 "\\|" ids-with-dot*
> >             "\\)" space*
> >             paren-exp
> >             "\\(?:" space* "]\\)*"      ; What's this for?
> >             "\\(?:" space* "\\<throws\\>" space* ids-with-dot-\[\]s*
> >                   "\\(?:," space* ids-with-dot-\[\]s* "\\)*"
> >             "\\)?"
> >             space*)))

> Can there be some typos in there or missing lines? I get a compiler warning
> for space+ being used in the let, should it be a let*? ids-with-dots is
> reported as not used. Can it be meant to be ids-with-dot*?
> ids-with-dot-\[\]s* is undefined!?

No, the regexp just wasn't tested right.  I made the mistake in
"testing" it of having all the things like space+ already defined as
defconsts.  So I failed to pick up the let which should have been let*
and giving all the uses of the bound variables their actual names.  :-(

Can I ask you to delete that buggy version and try the following
instead?  Thanks!

(defconst java-defun-prompt-regexp
  (let* ((space* "[ \t\n\r\f]*")
         (space+ "[ \t\n\r\f]+")
         (modifier*
          (concat "\\(?:"
                  (regexp-opt '("abstract" "const" "default" "final" "native"
                                "private" "protected" "public" "static"
                                "strictfp" "synchronized" "threadsafe"
                                "transient" "volatile")
                              'words)   ; Compatible with XEmacs
                  space+ "\\)*"))
         (ids-with-dots "[_$a-zA-Z][_$.a-zA-Z0-9]*")
         (ids-with-dot-\[\] "[[_$a-zA-Z][][_$.a-zA-Z0-9]*")
         (paren-exp "([^);{}]*)")
         (generic-exp "<[^(){};]*>"))
    (concat "^[ \t]*"
            modifier*
            "\\(?:" generic-exp space* "\\)?"
            ids-with-dot-\[\] space+                ; first part of type
            "\\(?:" ids-with-dot-\[\] space+ "\\)?" ; optional second part of type.
            "\\(?:[_a-zA-Z][^][ \t:;.,{}()=<>]*"    ; defun name
                "\\|" ids-with-dots
            "\\)" space*
            paren-exp
            "\\(?:" space* "]\\)*"      ; What's this for?
            "\\(?:" space* "\\<throws\\>" space* ids-with-dot-\[\]
                  "\\(?:," space* ids-with-dot-\[\] "\\)*"
            "\\)?"
            space*)))

> Yours
> -- 
> %% Mats

-- 
Alan Mackenzie (Nuremberg, Germany).





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

* bug#61436: Emacs Freezing With Java Files
  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>
  0 siblings, 1 reply; 33+ messages in thread
From: Mats Lidell via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-22 17:17 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Robert Weiner, Hank Greenburg, 61436-done, Eli Zaretskii,
	Robert Weiner, Jens Schmidt

Hi Alan,

> Alan Mackenzie writes:
> Can I ask you to delete that buggy version and try the following
> instead?  Thanks!

Looks good to me. With the regexp and using Emacs 30.0.50 I moved around,
jumping from function to function back and forth. I tested that with a few
java files including the one submitted with the initial bug report. During the
testing I did not experience any noticeable freeze.

%% Mats





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

* bug#61436: Emacs Freezing With Java Files
       [not found]                                         ` <CA+OMD9hgM_NX7GmeW8ph5fBW6SkFGogf4W4JOO5o62H3X15WHw@mail.gmail.com>
@ 2024-04-17 13:22                                           ` Alan Mackenzie
       [not found]                                           ` <Zh_JagP5xaaXJMOo@ACM>
  1 sibling, 0 replies; 33+ messages in thread
From: Alan Mackenzie @ 2024-04-17 13:22 UTC (permalink / raw)
  To: 61436

Hello, Bob.

On Tue, Apr 16, 2024 at 21:35:59 -0400, Robert Weiner wrote:
>    Hi Alan:
>    I just re-read this whole thread and realized you resolved the problem
>    for the Java defun-prompt-regexp but not the C++
>    defun-prompt-regexp in Hyperbole's hui-select.el:L404 (probably were
>    just tired after all of that).
>    Today, someone else reported that the C++ regexp was hanging their
>    Emacs.  Do you think you could pick this back up and rework the C++
>    regexp as you did the Java one?  It would be a big help; otherwise, I
>    think we'll just have to disable that functionality in Hyperbole.
>    Best regards,
>    Bob
>    On Sun, Oct 22, 2023 at 1:18â¯PM Mats Lidell
>    <[1]mats.lidell@lidells.se> wrote:

Yes, I'll happily finish off that C++ regexp.  I made considerable
progress with it back in October, getting smething basically working but
with some rough edges.  One problem is that the regexp was ~1600
characters long.  I don't know if this might make the program slow -
possibly not.

I've found the .el file I was working in, and located my notes from
October.  It's going to take longer than a day or two, but hopefully
less than a week or two.

[ .... ]

-- 
Alan Mackenzie (Nuremberg, Germany).





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

* bug#61436: Emacs Freezing With Java Files
       [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
  0 siblings, 2 replies; 33+ messages in thread
From: Alan Mackenzie @ 2024-04-17 18:50 UTC (permalink / raw)
  To: rswgnu; +Cc: Hank Greenburg, Mats Lidell, acm, Eli Zaretskii, Jens Schmidt,
	61436

Hello again, Bob.

On Wed, Apr 17, 2024 at 13:06:50 +0000, Alan Mackenzie wrote:
> On Tue, Apr 16, 2024 at 21:35:59 -0400, Robert Weiner wrote:
> >    Hi Alan:
> >    I just re-read this whole thread and realized you resolved the problem
> >    for the Java defun-prompt-regexp but not the C++
> >    defun-prompt-regexp in Hyperbole's hui-select.el:L404 (probably were
> >    just tired after all of that).
> >    Today, someone else reported that the C++ regexp was hanging their
> >    Emacs.  Do you think you could pick this back up and rework the C++
> >    regexp as you did the Java one?  It would be a big help; otherwise, I
> >    think we'll just have to disable that functionality in Hyperbole.
> >    Best regards,
> >    Bob
> >    On Sun, Oct 22, 2023 at 1:18â¯PM Mats Lidell
> >    <[1]mats.lidell@lidells.se> wrote:

> Yes, I'll happily finish off that C++ regexp.  I made considerable
> progress with it back in October, getting smething basically working but
> with some rough edges.  One problem is that the regexp was ~1600
> characters long.  I don't know if this might make the program slow -
> possibly not.

> I've found the .el file I was working in, and located my notes from
> October.  It's going to take longer than a day or two, but hopefully
> less than a week or two.

It was rather easier than I'd anticipated.  There is my first attempt
below.  It should find most C++ defun starts, but not all.  In particlar
it won't recognise one with nested parens or nested template delimiters;
regexps cannot handle arbitrary nesting,and it didn't seem worth the
trouble to code in a small bounded degree of nesting, though this surely
could be done if I'm wrong, here.

The regexp is not small.  At the latest count it was 2,223 characters
long.  I hope this won't affect performance too much.

Please try out this regexp, and let me know how well it's working.
Thanks!

> [ .... ]



(defconst c++-defun-prompt-regexp
  (let*
      ((space* "[ \t\n\r\f]*")
       (space+ "[ \t\n\r\f]+")
       (ad-hoc-requires-clause
	(concat "\\(?:requires" space* "[][()<> \t\n\r\f_$a-zA-Z0-9&|\"'+=.,*:~-]+" space* "\\)?"))
       (id (concat "[_$~a-zA-Z][_$a-zA-Z0-9]*")
	   ;; (concat "\\(\\(~" space* "\\)?" "\\([_$a-zA-Z][_$a-zA-Z0-9]*\\)\\)")
	   )
       (template-brackets "\\(?:<[^;{}]*>\\)")
       (id-<> (concat id "\\(?:" space* template-brackets "\\)?"))
       (id-:: (concat id-<> "\\(?:" space* "::" space* id-<> "\\)*"))
       (paren-exp "([^{};]*)")
       (template-exp\? (concat "\\(?:template" space* template-brackets space* "\\)?"))
       (type-prefix-modifier* (concat "\\(?:\\(?:"
				      "\\(?:\\<extern" space+ "\"[^\"]+\"\\)"
				      "\\|"
				      (regexp-opt '("auto" "const" "explicit" "extern"
						    "friend" "inline" "mutable"
						    "noexcept" "overload"
						    "register" "static" "typedef"
						    "virtual" "volatile")
						  'words)
				      "\\)"
				      space+
				      "\\)*"))
       (type-exp (concat
		  "\\(?:\\(?:" template-brackets space* "\\)?"
		  type-prefix-modifier*
		  "\\(?:\\(?:decltype" space* paren-exp space* "\\)"
		  "\\|"
		  "\\(?:"
		  "\\(?:class\\|enum\\|struct\\|typename\\|union\\)"
		  "\\(?:" space* "\\.\\.\\.\\)?\\)"
		  space+ id space*
		  "\\(?::" id-:: space* "\\)?"
		  "\\|"
		  id-:: space*
		  "\\)"
		  "\\)\\{1,2\\}"))
       (type-mid-modifier* (concat "\\(?:"
				   (regexp-opt
				    '("auto" "consteval" "constexpr"
				      "constinit" "explicit"
				      "extern" "friend" "inline"
				      "mutable" "noexcept" "register"
				      "static" "template"
				      "thread_local" "throw"
				      "virtual" "volatile")
				    'words)
				   space+ "\\)*"))
       (operator-exp (concat "\\(?:operator\\>" space*
			     "\\(?:[][a-z_+*/%^?&|!~<>,:=-]+"
			     "\\|()\\|\"\""
			     "\\)" space*
			     "\\)"))

       (name-exp			; matches foo or (* foo), etc.
	(concat "\\(?:(" space* "[*&]+" space* id-:: space* "[][()]*" ")"
		"\\|\\(?:[*&]+" space* "\\)?" id-::
		"\\)" space*))
       (type-suffix-modifier* (concat "\\(?:"
				      (regexp-opt
				       '("auto" "const" "noexcept"
					 "requires" "throw" "volatile")
				       'words)
				      space+ "\\)*"))
       (post-paren-modifier* (concat "\\(?:"
				     (regexp-opt
				      '("const" "final" "override"
					"mutable")
				      'words)
				     space* "\\)*")))

    (concat template-exp\?
	    "\\(?:" ad-hoc-requires-clause "\\)?"
	    type-exp
	    type-mid-modifier*
	    "\\(?:" operator-exp "\\|" name-exp "\\)"
	    type-suffix-modifier*
	    paren-exp space*
	    "\\(?:->" space* type-exp "\\)?"
	    post-paren-modifier*
	    "{"))


-- 
Alan Mackenzie (Nuremberg, Germany).





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

* bug#61436: Emacs Freezing With Java Files
  2024-04-17 18:50                                             ` Alan Mackenzie
@ 2024-04-17 22:24                                               ` Robert Weiner
  2024-04-19  2:19                                               ` Robert Weiner
  1 sibling, 0 replies; 33+ messages in thread
From: Robert Weiner @ 2024-04-17 22:24 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Hank Greenburg, Jens Schmidt, Eli Zaretskii, Mats Lidell, 61436

Great, will do, thanks, Alan.

-- Bob

> On Apr 17, 2024, at 2:50 PM, Alan Mackenzie <acm@muc.de> wrote:
> 
> Hello again, Bob.
> 
>> On Wed, Apr 17, 2024 at 13:06:50 +0000, Alan Mackenzie wrote:
>>> On Tue, Apr 16, 2024 at 21:35:59 -0400, Robert Weiner wrote:
>>>   Hi Alan:
>>>   I just re-read this whole thread and realized you resolved the problem
>>>   for the Java defun-prompt-regexp but not the C++
>>>   defun-prompt-regexp in Hyperbole's hui-select.el:L404 (probably were
>>>   just tired after all of that).
>>>   Today, someone else reported that the C++ regexp was hanging their
>>>   Emacs.  Do you think you could pick this back up and rework the C++
>>>   regexp as you did the Java one?  It would be a big help; otherwise, I
>>>   think we'll just have to disable that functionality in Hyperbole.
>>>   Best regards,
>>>   Bob
>>>   On Sun, Oct 22, 2023 at 1:18â¯PM Mats Lidell
>>>   <[1]mats.lidell@lidells.se> wrote:
> 
>> Yes, I'll happily finish off that C++ regexp.  I made considerable
>> progress with it back in October, getting smething basically working but
>> with some rough edges.  One problem is that the regexp was ~1600
>> characters long.  I don't know if this might make the program slow -
>> possibly not.
> 
>> I've found the .el file I was working in, and located my notes from
>> October.  It's going to take longer than a day or two, but hopefully
>> less than a week or two.
> 
> It was rather easier than I'd anticipated.  There is my first attempt
> below.  It should find most C++ defun starts, but not all.  In particlar
> it won't recognise one with nested parens or nested template delimiters;
> regexps cannot handle arbitrary nesting,and it didn't seem worth the
> trouble to code in a small bounded degree of nesting, though this surely
> could be done if I'm wrong, here.
> 
> The regexp is not small.  At the latest count it was 2,223 characters
> long.  I hope this won't affect performance too much.
> 
> Please try out this regexp, and let me know how well it's working.
> Thanks!
> 
>> [ .... ]
> 
> 
> 
> (defconst c++-defun-prompt-regexp
>  (let*
>      ((space* "[ \t\n\r\f]*")
>       (space+ "[ \t\n\r\f]+")
>       (ad-hoc-requires-clause
>    (concat "\\(?:requires" space* "[][()<> \t\n\r\f_$a-zA-Z0-9&|\"'+=.,*:~-]+" space* "\\)?"))
>       (id (concat "[_$~a-zA-Z][_$a-zA-Z0-9]*")
>       ;; (concat "\\(\\(~" space* "\\)?" "\\([_$a-zA-Z][_$a-zA-Z0-9]*\\)\\)")
>       )
>       (template-brackets "\\(?:<[^;{}]*>\\)")
>       (id-<> (concat id "\\(?:" space* template-brackets "\\)?"))
>       (id-:: (concat id-<> "\\(?:" space* "::" space* id-<> "\\)*"))
>       (paren-exp "([^{};]*)")
>       (template-exp\? (concat "\\(?:template" space* template-brackets space* "\\)?"))
>       (type-prefix-modifier* (concat "\\(?:\\(?:"
>                      "\\(?:\\<extern" space+ "\"[^\"]+\"\\)"
>                      "\\|"
>                      (regexp-opt '("auto" "const" "explicit" "extern"
>                            "friend" "inline" "mutable"
>                            "noexcept" "overload"
>                            "register" "static" "typedef"
>                            "virtual" "volatile")
>                          'words)
>                      "\\)"
>                      space+
>                      "\\)*"))
>       (type-exp (concat
>          "\\(?:\\(?:" template-brackets space* "\\)?"
>          type-prefix-modifier*
>          "\\(?:\\(?:decltype" space* paren-exp space* "\\)"
>          "\\|"
>          "\\(?:"
>          "\\(?:class\\|enum\\|struct\\|typename\\|union\\)"
>          "\\(?:" space* "\\.\\.\\.\\)?\\)"
>          space+ id space*
>          "\\(?::" id-:: space* "\\)?"
>          "\\|"
>          id-:: space*
>          "\\)"
>          "\\)\\{1,2\\}"))
>       (type-mid-modifier* (concat "\\(?:"
>                   (regexp-opt
>                    '("auto" "consteval" "constexpr"
>                      "constinit" "explicit"
>                      "extern" "friend" "inline"
>                      "mutable" "noexcept" "register"
>                      "static" "template"
>                      "thread_local" "throw"
>                      "virtual" "volatile")
>                    'words)
>                   space+ "\\)*"))
>       (operator-exp (concat "\\(?:operator\\>" space*
>                 "\\(?:[][a-z_+*/%^?&|!~<>,:=-]+"
>                 "\\|()\\|\"\""
>                 "\\)" space*
>                 "\\)"))
> 
>       (name-exp            ; matches foo or (* foo), etc.
>    (concat "\\(?:(" space* "[*&]+" space* id-:: space* "[][()]*" ")"
>        "\\|\\(?:[*&]+" space* "\\)?" id-::
>        "\\)" space*))
>       (type-suffix-modifier* (concat "\\(?:"
>                      (regexp-opt
>                       '("auto" "const" "noexcept"
>                     "requires" "throw" "volatile")
>                       'words)
>                      space+ "\\)*"))
>       (post-paren-modifier* (concat "\\(?:"
>                     (regexp-opt
>                      '("const" "final" "override"
>                    "mutable")
>                      'words)
>                     space* "\\)*")))
> 
>    (concat template-exp\?
>        "\\(?:" ad-hoc-requires-clause "\\)?"
>        type-exp
>        type-mid-modifier*
>        "\\(?:" operator-exp "\\|" name-exp "\\)"
>        type-suffix-modifier*
>        paren-exp space*
>        "\\(?:->" space* type-exp "\\)?"
>        post-paren-modifier*
>        "{"))
> 
> 
> --
> Alan Mackenzie (Nuremberg, Germany).





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

* bug#61436: Emacs Freezing With Java Files
  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
  1 sibling, 1 reply; 33+ messages in thread
From: Robert Weiner @ 2024-04-19  2:19 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Hank Greenburg, Jens Schmidt, Eli Zaretskii, Mats Lidell, 61436

[-- Attachment #1: Type: text/plain, Size: 242 bytes --]

Hi Alan:

I'm starting to look at your rewrite of the c++-defun-prompt-regexp.  I am
wondering if we need one for the equivalent java regexp or if the patch you
mention in your prior message is all that should be needed there.

Regards,

Bob

[-- Attachment #2: Type: text/html, Size: 809 bytes --]

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

* bug#61436: Emacs Freezing With Java Files
  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
@ 2024-04-19  2:58                           ` Robert Weiner
  2 siblings, 0 replies; 33+ messages in thread
From: Robert Weiner @ 2024-04-19  2:58 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Hank Greenburg, Jens Schmidt, Eli Zaretskii, Mats Lidell, 61436

[-- Attachment #1: Type: text/plain, Size: 6009 bytes --]

Hi Alan:

This is to confirm that I have tested your cc-defs.el patch works properly
and eliminates the Emacs hang when using the Hyperbole
java-defun-prompt-regexp.  Nice work.

Regards,

Bob


On Fri, Oct 13, 2023 at 8:42 AM Alan Mackenzie <acm@muc.de> wrote:

> Hello, Jens.
>
> On Thu, Oct 12, 2023 at 21:58:06 +0200, Jens Schmidt wrote:
> > Hi Alan,
>
> > Alan Mackenzie <acm@muc.de> writes:
>
> [ .... ]
>
> > >> That always freezes Emacs (29 and master) even before it has a chance
> to
> > >> display P1.java.  The freeze happens in function
> > >> `c-get-fallback-scan-pos', where the while loop inf-loops.
>
> Yes.
>
> > > c-get-fallback-scan-pos tries to move to the beginning of a function.
> > > This probably involves defun-prompt-regexp when it is non-nil.  :-(
>
> > Otherwise we would see hangs or exponential behavior (?) somewhere in
> > the Emacs regexp machinerie, but they take place in that while loop.  So
> > I guess that there must be some other, additional quality that this
> > regexp fulfills.  Like: "matches the empty string" (which it does not,
> > as far as I can tell) or: "must only match before curlies" or whatnot.
>
> > Unfortunately, the doc string/info doc of `defun-prompt-regexp´ provides
> > only exactly that latter criterion:
>
> >   That is to say, a defun begins on a line that starts with a match for
> >   this regular expression, followed by a character with open-parenthesis
> >   syntax.
>
> > I guess that only pruning that regexp until things start unfreezing
> > could give an answer here.  Or more tracing to see how point moves in
> > `c-get-fallback-scan-pos'.  But I need some tracing break here ...
>
>
> > ... or so I thought, I just couldn't resist:
>
> > I expanded and instrumented that function from emacs-29 as follows,
> > (hopefully) not changing any of its logic:
>
> > ------------------------- snip -------------------------
> > (defun c-get-fallback-scan-pos (here)
> >   ;; Return a start position for building `c-state-cache' from scratch.
> This
> >   ;; will be at the top level, 2 defuns back.  Return nil if we don't
> find
> >   ;; these defun starts a reasonable way back.
> >   (message "c-get-fallback-scan-pos")
> >   (save-excursion
> >     (save-restriction
> >       (when (> here (* 10 c-state-cache-too-far))
> >       (narrow-to-region (- here (* 10 c-state-cache-too-far)) here))
> >       ;; Go back 2 bods, but ignore any bogus positions returned by
> >       ;; beginning-of-defun (i.e. open paren in column zero).
> >       (goto-char here)
> >       (let ((cnt 2))
> >       (message "beginning-of-defun-loop-00: %d %d" cnt (point))
> >       (while (not (or (bobp) (zerop cnt)))
> >         (message "beginning-of-defun-loop-01: %d" (point))
> >         (let (beginning-of-defun-function end-of-defun-function)
> >           (beginning-of-defun))
> >         (and defun-prompt-regexp
> >              (looking-at defun-prompt-regexp)
> >              (message "beginning-of-defun-loop-02: %d" (point))
> >              (goto-char (match-end 0)))
> >         (message "beginning-of-defun-loop-03: %d" (point))
> >         (if (eq (char-after) ?\{)
> >             (setq cnt (1- cnt)))))
> >       (and (not (bobp))
> >          (point)))))
> > ------------------------- snip -------------------------
>
> > That results in the message triple
>
> > ------------------------- snip -------------------------
> > beginning-of-defun-loop-01: 5879
> > beginning-of-defun-loop-02: 5801
> > beginning-of-defun-loop-03: 5879
> > beginning-of-defun-loop-01: 5879
> > beginning-of-defun-loop-02: 5801
> > beginning-of-defun-loop-03: 5879
> > ...
> > ------------------------- snip -------------------------
>
> > inf-looping.  These points are (|: 5801, ^: 5879) here in P1.java:
>
> > ------------------------- snip -------------------------
> > 178    } catch (Exception e) {
> > 179|      error("symTable.addDecl", "unexpected error with a single
> HashMap " + e)^;
> > 180    }
> > 181
> > ------------------------- snip -------------------------
>
> > So the catch-block just before line 181 is recognized as a potential BOD
> > (previous trailing open curly?).  But then `defun-prompt-regexp' matches
> > the function call in the catch-block as defun prompt regexp (which it
> > better should not?), taking point back to where, on next BOD search, the
> > exact previous BOD is found again.
>
> > So probably there are really two issues here:
>
> > 1. The `defun-prompt-regexp' used by Hyperbole, which matches too
> >    broadly, and
>
> > 2. function `c-get-fallback-scan-pos', which could try harder to avoid
> >    inf-loops when such things happen.
>
> > But that's where I *really* stop here :-)
>
> You've diagnosed the bug completely.  Thanks!  The hang was caused
> entirely by the loop in c-get-fallback-scan-pos, not the deficiencies in
> that long regexp.
>
> defun-prompt-regexp, when appended with a \\s( (as is done in
> beginning-of-defun-raw) matches the "      error(" on L179 of P1.java.
> The bare defun-prompt-regexp (as used in CC Mode) matches the entire
> line except the terminating ;.  This regexp could do with some
> amendment, but it is not the main cause of the bug.
>
> To solve the bug, I'm amending the macro c-beginning-of-defun-1 so that
> it only stops at a debug-prompt-regexp position when it also found a {.
> Otherwise it will keep looping until it finds a better position or BOB.
>
> Would all concerned please apply the attached patch to the Emacs master
> branch, directory lisp/progmodes.  Then please byte compile CC Mode in
> full (a macro has been changed), and try the result on your real Java
> code.  (If anybody wants any help applying the patch or byte compiling,
> feel free to send me private mail.)  Then please confirm that the bug is
> indeed fixed.  Thanks!
>
> --
> Alan Mackenzie (Nuremberg, Germany).
>
>

[-- Attachment #2: Type: text/html, Size: 7755 bytes --]

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

* bug#61436: Emacs Freezing With Java Files
  2024-04-19  2:19                                               ` Robert Weiner
@ 2024-04-19  4:40                                                 ` Robert Weiner
  2024-04-19 15:59                                                   ` Alan Mackenzie
  0 siblings, 1 reply; 33+ messages in thread
From: Robert Weiner @ 2024-04-19  4:40 UTC (permalink / raw)
  To: rswgnu; +Cc: Hank Greenburg, Mats Lidell, acm, Eli Zaretskii, Jens Schmidt,
	61436

If we do need your c++ regexp, do we have a repeatable test that generates the hang, as I cannot generate such a problem even without your patch while using the prior Hyperbole c++ regexp.


-- Bob

> On Apr 18, 2024, at 10:19 PM, Robert Weiner <rsw@gnu.org> wrote:
> 
> 
> Hi Alan:
> 
> I'm starting to look at your rewrite of the c++-defun-prompt-regexp.  I am wondering if we need one for the equivalent java regexp or if the patch you mention in your prior message is all that should be needed there.
> 
> Regards,
> 
> Bob





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

* bug#61436: Emacs Freezing With Java Files
  2024-04-19  4:40                                                 ` Robert Weiner
@ 2024-04-19 15:59                                                   ` Alan Mackenzie
  0 siblings, 0 replies; 33+ messages in thread
From: Alan Mackenzie @ 2024-04-19 15:59 UTC (permalink / raw)
  To: Robert Weiner
  Cc: Hank Greenburg, Mats Lidell, acm, Eli Zaretskii, Jens Schmidt,
	61436

Hello, Bob.

On Fri, Apr 19, 2024 at 00:40:19 -0400, Robert Weiner wrote:
> If we do need your c++ regexp, do we have a repeatable test that
> generates the hang, as I cannot generate such a problem even without
> your patch while using the prior Hyperbole c++ regexp.

I'm afraid I don't (yet) have a repeatable test case.  I have a raw
init.el file from pillowtrucker@proton.me, but it's quite some work to
extract a test procedure from it.  This is a separate bug involving
hanging in a C++ file, but I noticed it was using hyperbole and H's value
of defun-prompt-regexp was set.

> -- Bob

> > On Apr 18, 2024, at 10:19 PM, Robert Weiner <rsw@gnu.org> wrote:

> > 
> > Hi Alan:

> > I'm starting to look at your rewrite of the c++-defun-prompt-regexp.
> > I am wondering if we need one for the equivalent java regexp or if
> > the patch you mention in your prior message is all that should be
> > needed there.

> > Regards,

> > Bob

-- 
Alan Mackenzie (Nuremberg, Germany).





^ 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).