Skip to content

Commit

Permalink
Merge pull request #26 from andreluisos/25-implement-java-file-creation
Browse files Browse the repository at this point in the history
Implement Java file creation
  • Loading branch information
andreluisos authored Nov 12, 2024
2 parents b996911 + 701e95d commit f6ba974
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 1 deletion.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Among with bug fixing, I also plan to:

- [ ] Create DTO for an entity (WIP)
- [ ] Implement UI for JPA repository creation
- [ ] Create Java files (enum, interface, annotation, class, record)
- [x] Create Java files (enum, interface, annotation, class, record)
- [ ] Implement Spring Initializr and project loading
- [ ] Runner for Java applications
- [ ] Figure out a way to create tests
Expand All @@ -86,6 +86,7 @@ The plugin includes a range of features, each powered by dedicated Tree-sitter q
![JPA Entity creation](https://github.com/andreluisos/nvim-jpagenie/blob/media/create_entity.gif)

## Easily add Entity attributes

- ID attributes
- Basic type attributes
- Enum type attributes
Expand All @@ -95,6 +96,7 @@ The plugin includes a range of features, each powered by dedicated Tree-sitter q
![Entity enum attribute creation](https://github.com/andreluisos/nvim-jpagenie/blob/media/create_enum_attribute.gif)

## Quickly create Entity relationships

- Many-to-one relationships
- One-to-one relationships
- Many-to-one relationships with automatic equals() and hashCode() method generation
Expand Down
8 changes: 8 additions & 0 deletions rplugin/python3/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pynvim.api.nvim import Nvim

from constants.java_basic_types import JAVA_BASIC_TYPES
from utils.java_file_utils import JavaFileLib
from utils.common_utils import CommonUtils
from utils.entity_creation_utils import EntityCreationUtils
from utils.entity_field_utils import EntityFieldUtils
Expand Down Expand Up @@ -64,3 +65,10 @@ def __init__(self, nvim: Nvim) -> None:
common_utils=self.common_utils,
logging=self.logging,
)
self.java_file_utils = JavaFileLib(
nvim=self.nvim,
logging=self.logging,
treesitter_utils=self.treesitter_utils,
path_utils=self.path_utils,
common_utils=self.common_utils,
)
16 changes: 16 additions & 0 deletions rplugin/python3/custom_types/create_java_file_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from dataclasses import dataclass, field, InitVar
from custom_types.java_file_type import JavaFileType


@dataclass
class CreateJavaFileArgs:
package_path: str
file_name: str
file_type: InitVar[str]
file_type_enum: JavaFileType = field(init=False)

def __post_init__(
self,
file_type: str,
):
self.file_type_enum = JavaFileType.from_value(file_type)
16 changes: 16 additions & 0 deletions rplugin/python3/custom_types/java_file_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from enum import Enum


class JavaFileType(Enum):
CLASS = "class"
INTERFACE = "interface"
RECORD = "record"
ENUM = "enum"
ANNOTATION = "annotation"

@classmethod
def from_value(cls, value: str) -> "JavaFileType":
for member in cls:
if member.value == value:
return member
raise ValueError(f"No matching enum member for value '{value}'")
41 changes: 41 additions & 0 deletions rplugin/python3/file_creation_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from typing import Dict, List
from pynvim import plugin, command, function
from pynvim.api import Nvim

from base import Base
from custom_types.log_level import LogLevel
from custom_types.create_java_file_args import CreateJavaFileArgs


@plugin
class JavaFileCreationCommands(Base):
def __init__(self, nvim: Nvim) -> None:
super().__init__(nvim)
self.debug: bool = False

@command("CreateNewJavaFile", nargs="*")
def create_java_file(self, args: List[str]) -> None:
self.logging.reset_log_file()
if len(args) > 1:
error_msg = "Only one arg is allowed"
self.logging.log(error_msg, LogLevel.ERROR)
raise ValueError(error_msg)
self.debug = True if "debug" in args else False
root_package_path = str(self.path_utils.get_spring_root_package_path(True))
self.nvim.exec_lua(
self.common_utils.read_ui_file_as_string("create_java_file.lua"),
(
self.ui_path,
root_package_path,
),
)

@function("CreateNewJavaFileCallback")
def create_new_java_file_callback(self, args: List[Dict]):
converted_args = CreateJavaFileArgs(**args[0])
if self.debug:
self.logging.log(f"Converted args: {converted_args}", LogLevel.DEBUG)
self.java_file_utils.create_java_file(
args=converted_args,
debug=self.debug,
)
90 changes: 90 additions & 0 deletions rplugin/python3/ui/create_java_file.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
local args = ...

package.path = package.path .. ";" .. args[1] .. "/?.lua"

local select_one = require("select_one")

local n = require("nui-components")

local renderer = n.create_renderer({
width = 65,
height = 15,
})

local signal = n.create_signal({
file_name = "NewFile",
file_type = "class",
package_path = args[2],
})

local function render_main_title()
return n.rows(
{ flex = 0 },
n.paragraph({
lines = {
n.line(n.text("New Java file", "String")),
},
align = "center",
is_focusable = false,
})
)
end

local function render_text_input_component(title, signal_key, signal_hidden, autofocus)
return n.text_input({
size = 1,
autofocus = autofocus or false,
value = signal[signal_key],
border_label = title,
on_change = function(value, _)
signal[signal_key] = value
end,
hidden = signal[signal_hidden] or false,
})
end

local function render_file_type_component(_signal)
local data = {
n.node({ text = "Class", is_done = true, id = "class" }),
n.node({ text = "Interface", is_done = false, id = "interface" }),
n.node({ text = "Record", is_done = false, id = "record" }),
n.node({ text = "Enum", is_done = false, id = "enum" }),
n.node({ text = "Annotation", is_done = false, id = "annotation" }),
}
return select_one.render_component(nil, "File type", data, "file_type", _signal)
end

local function render_confirm_button()
return n.button({
flex = 1,
label = "Confirm",
align = "center",
global_press_key = "<C-CR>",
padding = { top = 1 },
on_press = function()
local result = {
file_name = signal.file_name:get_value(),
file_type = signal.file_type:get_value(),
package_path = signal.package_path:get_value(),
}
vim.call("CreateNewJavaFileCallback", result)
renderer:close()
end,
hidden = signal.confirm_btn_hidden,
})
end

local function render_component()
return n.rows(
{ flex = 0 },
render_main_title(),
n.gap(1),

render_text_input_component("File name", "file_name", nil, true),
render_text_input_component("Package path", "package_path", nil, false),
render_file_type_component(signal),
render_confirm_button()
)
end

renderer:render(render_component())
83 changes: 83 additions & 0 deletions rplugin/python3/utils/java_file_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from pathlib import Path

from custom_types.log_level import LogLevel
from custom_types.create_java_file_args import CreateJavaFileArgs
from custom_types.java_file_type import JavaFileType
from utils.path_utils import PathUtils
from utils.common_utils import CommonUtils
from utils.treesitter_utils import TreesitterUtils
from utils.logging import Logging


class JavaFileLib:
def __init__(
self,
nvim,
logging: Logging,
treesitter_utils: TreesitterUtils,
path_utils: PathUtils,
common_utils: CommonUtils,
):
self.nvim = nvim
self.logging = logging
self.treesitter_utils = treesitter_utils
self.path_utils = path_utils
self.common_utils = common_utils

def get_boiler_plate(
self,
file_type: JavaFileType,
package_path: str,
file_name: str,
debug: bool = False,
) -> bytes:
boiler_plates = {
"class": f"""package {package_path};\n\npublic class {file_name} {{\n\n}}""",
"interface": f"""package {package_path};\n\npublic interface {file_name} {{\n\n}}""",
"enum": f"""package {package_path};\n\npublic enum {file_name} {{\n\n}}""",
"record": f"""package {package_path};\n\npublic record {file_name}(\n\n) {{}}""",
"annotation": f"""package {package_path};\n\npublic @interface {file_name} {{\n\n}}""",
}
boiler_plate = boiler_plates.get(file_type.value, "")
if debug:
self.logging.log(
f"Boiler plate: {boiler_plate}",
LogLevel.DEBUG,
)
return boiler_plate.encode("utf-8")

def get_file_path(
self,
package_path: str,
file_name: str,
debug: bool = False,
) -> Path:
main_class_path = self.path_utils.get_spring_main_class_path()
base_path = self.common_utils.get_base_path(main_class_path)
relative_path = self.common_utils.get_relative_path(package_path)
file_path = self.common_utils.construct_file_path(
base_path, relative_path, file_name
)
if debug:
self.logging.log(
[
f"Base path: {str(base_path)}",
f"Relative path: {str(relative_path)}",
f"File path: {str(file_path.parent)}",
f"Successfully created: {file_path}",
],
LogLevel.DEBUG,
)
return file_path

def create_java_file(
self,
args: CreateJavaFileArgs,
debug: bool = False,
) -> None:
boiler_plate = self.get_boiler_plate(
args.file_type_enum, args.package_path, args.file_name, debug
)
file_path = self.get_file_path(args.package_path, args.file_name, debug)
file_tree = self.treesitter_utils.convert_bytes_to_tree(boiler_plate)
self.treesitter_utils.update_buffer(file_tree, file_path, True)

0 comments on commit f6ba974

Please sign in to comment.