diff --git a/modules/feature/file-templates/templates/java-mode/.yas-setup.el b/modules/feature/file-templates/templates/java-mode/.yas-setup.el index f4143072e..b00feed7e 100644 --- a/modules/feature/file-templates/templates/java-mode/.yas-setup.el +++ b/modules/feature/file-templates/templates/java-mode/.yas-setup.el @@ -1,11 +1,9 @@ (defun yas-java-project-package () - (if (eq major-mode 'java-mode) - (s-chop-suffix "." (s-replace "/" "." (f-dirname (f-relative (buffer-file-name) - (concat (narf/project-root) "/src/"))))) - "")) + (or (and (eq major-mode 'java-mode) + (+java-current-package)) + "")) (defun yas-java-class-name () - (if (eq major-mode 'java-mode) - (f-no-ext (f-base (buffer-file-name))) - "")) - + (or (and (eq major-mode 'java-mode) + (+java-current-class)) + "")) diff --git a/modules/lang/java/autoload.el b/modules/lang/java/autoload.el index fa1689503..45c27aa1e 100644 --- a/modules/lang/java/autoload.el +++ b/modules/lang/java/autoload.el @@ -30,3 +30,42 @@ (android-mode +1) (doom/set-build-command "./gradlew %s" "build.gradle"))) +;;;###autoload +(defun +java-current-package () + "Converts the current file's path into a namespace. + +For example: ~/some/project/src/net/lissner/game/MyClass.java +Is converted to: net.lissner.game + +It does this by ignoring everything before the nearest package root (see +`+java-project-package-roots' to control what this function considers a package +root)." + (unless (eq major-mode 'java-mode) + (user-error "Not in a java-mode buffer")) + (let* ((project-root (file-truename (doom-project-root))) + (file-path (file-name-sans-extension + (file-truename (or buffer-file-name + default-directory)))) + (src-root (cl-loop for root in +java-project-package-roots + if (and (stringp root) + (locate-dominating-file file-path root)) + return (file-name-directory (file-relative-name file-path (expand-file-name root it))) + if (and (integerp root) + (> root 0) + (let* ((parts (split-string (file-relative-name file-path project-root) "/")) + (fixed-parts (reverse (nbutlast (reverse parts) root)))) + (when fixed-parts + (string-join fixed-parts "/")))) + return it))) + (when src-root + (string-remove-suffix "." (replace-regexp-in-string "/" "." src-root))))) + +;;;###autoload +(defun +java-current-class () + "Get the class name for the current file." + (unless (eq major-mode 'java-mode) + (user-error "Not in a java-mode buffer")) + (unless buffer-file-name + (user-error "This buffer has no filepath; cannot guess its class name")) + (or (file-name-sans-extension (file-name-base (buffer-file-name))) + "ClassName")) diff --git a/modules/lang/java/config.el b/modules/lang/java/config.el index 9e42b0b62..5e1e07d5b 100644 --- a/modules/lang/java/config.el +++ b/modules/lang/java/config.el @@ -1,5 +1,26 @@ ;;; lang/java/config.el -*- lexical-binding: t; -*- +(defvar +java-project-package-roots (list "java/" "test/" "main/" "src/" 1) + "A list of relative directories (strings) or depths (integer) used by +`+java-current-package' to delimit the namespace from the current buffer's full +file path. Each root is tried in sequence until one is found. + +If a directory is encountered in the file path, everything before it (including +it) will be ignored when converting the path into a namespace. + +An integer depth is how many directories to pop off the start of the relative +file path (relative to the project root). e.g. + +Say the absolute path is ~/some/project/src/java/net/lissner/game/MyClass.java +The project root is ~/some/project +If the depth is 1, the first directory in src/java/net/lissner/game/MyClass.java + is removed: java.net.lissner.game. +If the depth is 2, the first two directories are removed: net.lissner.game.") + + +;; +;; java-mode + (add-hook 'java-mode-hook #'rainbow-delimiters-mode) (cond ((featurep! +meghanada) (load! "+meghanada"))