From ac000dafeb2c03d7ffbedb310b9e5266fa56a7a9 Mon Sep 17 00:00:00 2001 From: Andrew Charneski Date: Tue, 16 Apr 2024 23:53:36 -0400 Subject: [PATCH] 1.4.2 (#153) * 1.4.3 * 1.4.2 * docs * wip * renames, etc --- CHANGELOG.md | 2 +- README.md | 2 +- action_documentation.md | 1730 --------- build.gradle.kts | 4 +- counters.json | 12 - docs/action_documentation.md | 3388 ++++++++--------- docs/action_readme.md | 135 +- docs/actions.md | 60 +- docs/code_review.md | 50 +- docs/coding_standards.md | 70 + docs/configuration.md | 88 + docs/feature_roadmap.md | 64 +- docs/manual_tests.md | 2642 +++++++++++++ docs/prompt_documentation.md | 1318 +++++++ gradle.properties | 2 +- .../github/simiacryptus/aicoder/AppServer.kt | 114 + .../aicoder/actions/BaseAction.kt | 54 +- .../aicoder/actions/SelectionAction.kt | 4 +- .../aicoder/actions/code/CustomEditAction.kt | 47 +- .../aicoder/actions/code/DescribeAction.kt | 12 +- .../aicoder/actions/code/PasteAction.kt | 89 +- .../actions/code/RecentCodeEditsAction.kt | 3 + .../actions/{generic => code}/RedoLast.kt | 4 +- .../aicoder/actions/dev/AppServer.kt | 118 - .../{generic => dev}/LineFilterChatAction.kt | 11 +- .../aicoder/actions/dev/PrintTreeAction.kt | 3 +- .../actions/generic/AnalogueFileAction.kt | 169 - .../aicoder/actions/generic/AppendAction.kt | 32 - .../aicoder/actions/generic/AutoDevAction.kt | 320 -- .../aicoder/actions/generic/CodeChatAction.kt | 4 +- .../actions/generic/CreateFileAction.kt | 95 - .../CreateFileFromDescriptionAction.kt | 97 + .../aicoder/actions/generic/DiffChatAction.kt | 44 +- .../generic/DocumentationCompilerAction.kt | 233 -- .../generic/GenerateDocumentationAction.kt | 236 ++ .../generic/GenerateRelatedFileAction.kt | 158 + .../actions/generic/GenericChatAction.kt | 83 + .../actions/generic/MultiDiffChatAction.kt | 116 +- .../actions/generic/MultiStepPatchAction.kt | 300 ++ ...TaskRunnerAction.kt => PlanAheadAction.kt} | 59 +- ...on.kt => WebDevelopmentAssistantAction.kt} | 58 +- .../actions/git/PrintGitCommitPatchAction.kt | 41 - .../legacy/AppendTextWithChatAction.kt | 35 + .../{code => legacy}/CommentsAction.kt | 14 +- .../actions/{code => legacy}/DocAction.kt | 14 +- .../{code => legacy}/ImplementStubAction.kt | 17 +- .../InsertImplementationAction.kt | 16 +- .../{code => legacy}/RenameVariablesAction.kt | 23 +- .../ReplaceWithSuggestionsAction.kt} | 29 +- .../VoiceToTextAction.kt} | 15 +- .../markdown/MarkdownImplementActionGroup.kt | 17 +- .../actions/markdown/MarkdownListAction.kt | 10 +- .../aicoder/config/AppSettingsComponent.kt | 9 +- .../aicoder/config/AppSettingsConfigurable.kt | 18 +- .../aicoder/config/AppSettingsState.kt | 3 +- .../simiacryptus/aicoder/config/MRUItems.kt | 2 +- .../config/StaticAppSettingsConfigurable.kt | 2 +- .../simiacryptus/aicoder/config/UIAdapter.kt | 102 +- .../simiacryptus/aicoder/config/UsageTable.kt | 183 +- .../aicoder/ui/ConsolidatedWidgetFactory.kt | 145 + .../aicoder/ui/ModelSelectionWidgetFactory.kt | 166 +- .../ui/TemperatureControlWidgetFactory.kt | 15 +- .../aicoder/util/CheckboxTaskManager.kt | 49 - .../aicoder/util/CodeChatSocketManager.kt | 36 +- .../aicoder/util/ComputerLanguage.kt | 8 + .../aicoder/util/IdeaOpenAIClient.kt | 380 +- .../simiacryptus/aicoder/util/LineComment.kt | 5 +- .../aicoder/util/PluginStartupActivity.kt | 26 +- .../simiacryptus/aicoder/util/UITools.kt | 1636 ++++---- .../aicoder/util/psi/PsiClassContext.kt | 7 +- .../simiacryptus/aicoder/util/psi/PsiUtil.kt | 1 + src/main/kotlin/icons/MyIcons.kt | 14 + src/main/resources/META-INF/plugin.xml | 84 +- src/main/resources/welcomePage.md | 8 +- .../aicoder/ApplicationDevelopmentUITest.kt | 4 +- .../github/simiacryptus/aicoder/UITestUtil.kt | 24 +- .../aicoder/actions/ActionTestBase.kt | 2 +- .../actions/code/CommentsActionTest.kt | 4 +- .../actions/code/CustomEditActionTest.kt | 3 +- .../actions/code/DescribeActionTest.kt | 3 +- .../aicoder/actions/code/DocActionTest.kt | 4 +- .../actions/code/ImplementStubActionTest.kt | 4 +- .../code/InsertImplementationActionTest.kt | 4 +- .../actions/code/RenameVariablesActionTest.kt | 1 + .../actions/generic/AnalogueFileActionTest.kt | 2 +- .../actions/generic/AppendActionTest.kt | 10 +- .../actions/generic/CreateFileActionTest.kt | 2 +- .../actions/generic/PasteActionTest.kt | 3 +- .../generic/ReplaceOptionsActionTest.kt | 7 +- .../aicoder/util/ApxPatchUtilTest.kt | 16 +- .../aicoder/util/DiffMatchPatchTest.kt | 182 +- .../aicoder/util/MarkdownProcessor.kt | 8 +- usage_log.csv | 2 - 93 files changed, 8804 insertions(+), 6641 deletions(-) delete mode 100644 action_documentation.md delete mode 100644 counters.json create mode 100644 docs/coding_standards.md create mode 100644 docs/configuration.md create mode 100644 docs/manual_tests.md create mode 100644 docs/prompt_documentation.md create mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/AppServer.kt rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/{generic => code}/RedoLast.kt (82%) delete mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/AppServer.kt rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/{generic => dev}/LineFilterChatAction.kt (93%) delete mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AnalogueFileAction.kt delete mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AppendAction.kt delete mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AutoDevAction.kt delete mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileAction.kt create mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileFromDescriptionAction.kt delete mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DocumentationCompilerAction.kt create mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateDocumentationAction.kt create mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateRelatedFileAction.kt create mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenericChatAction.kt create mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiStepPatchAction.kt rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/{TaskRunnerAction.kt => PlanAheadAction.kt} (96%) rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/{WebDevAction.kt => WebDevelopmentAssistantAction.kt} (91%) delete mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/PrintGitCommitPatchAction.kt create mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/AppendTextWithChatAction.kt rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/{code => legacy}/CommentsAction.kt (76%) rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/{code => legacy}/DocAction.kt (87%) rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/{code => legacy}/ImplementStubAction.kt (83%) rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/{code => legacy}/InsertImplementationAction.kt (90%) rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/{code => legacy}/RenameVariablesAction.kt (82%) rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/{generic/ReplaceOptionsAction.kt => legacy/ReplaceWithSuggestionsAction.kt} (74%) rename src/main/kotlin/com/github/simiacryptus/aicoder/actions/{generic/DictationAction.kt => legacy/VoiceToTextAction.kt} (91%) create mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/ui/ConsolidatedWidgetFactory.kt delete mode 100644 src/main/kotlin/com/github/simiacryptus/aicoder/util/CheckboxTaskManager.kt create mode 100644 src/main/kotlin/icons/MyIcons.kt delete mode 100644 usage_log.csv diff --git a/CHANGELOG.md b/CHANGELOG.md index 06981b88..c73d5772 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ - `DiffChatAction`: A new action for engaging in a chat session to generate and apply code diffs directly within the IDE. - `MultiDiffChatAction`: Allows for collaborative code review and diff generation across multiple files. -- `AutoDevAction`: Automates development tasks by translating user directives into actionable development tasks and code +- `MultiStepPatchAction`: Automates development tasks by translating user directives into actionable development tasks and code modifications. - Support for models from https://www.perplexity.ai/, https://console.groq.com/, and https://modelslab.com/dashboard/, enhancing the plugin's versatility and performance in code generation and analysis. diff --git a/README.md b/README.md index c64118e5..0754d8fb 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ game-changing features via the context menu within your editor or project view: * 💬 **DiffChatAction & MultiDiffChatAction**: Collaborate effortlessly with AI-powered chat sessions that generate and apply code diffs across single or multiple files. -* 🚀 **AutoDevAction**: Transform user directives into actionable development tasks and code modifications, automating +* 🚀 **MultiStepPatchAction**: Transform user directives into actionable development tasks and code modifications, automating key aspects of your workflow. * 📊 **mermaid.js Integration**: Visualize your code and ideas with stunning diagrams generated using the mermaid.js diff --git a/action_documentation.md b/action_documentation.md deleted file mode 100644 index 7f5be0c7..00000000 --- a/action_documentation.md +++ /dev/null @@ -1,1730 +0,0 @@ -# Project User Documentation - -Welcome to the user documentation for our IntelliJ IDEA plugin suite, designed to enhance your development experience -with a variety of actions. This document provides an overview of the available actions, categorized for easy reference, -and instructions on how to use them to improve your coding efficiency. - -## Table of Categorized Actions - -- `DiffChatAction`: Engages in a chat session to generate and apply code diffs directly within the IDE. -- **Collaboration and Review** - - `DiffChatAction`: Initiates a chat session for collaborative code review and diff generation. - - `MultiDiffChatAction`: Allows for collaborative code review and diff generation across multiple files. - - `LineFilterChatAction`: Provides an interactive chat interface for discussing specific lines of code. - - `CodeChatAction`: Offers a real-time chat interface for discussing code snippets and receiving AI-powered coding assistance. - -## How to Use Actions - -- **Code Editing Actions** - - `CustomEditAction`: Trigger this action to open a dialog where you can input a natural language instruction for - editing your selected code. - - `ImplementStubAction`: Automatically selects code elements that match stub patterns and implements them based on - AI suggestions. - - `PasteAction`: Simply copy text to your clipboard and use this action to paste it as converted code in your - editor. - - `RenameVariablesAction`: Select a block of code and trigger this action to receive suggestions for renaming - variables. -- **Documentation Actions** - - `DocAction`: Select a code block and activate this action to generate and insert documentation above the selected - block. - - `DocumentationCompilerAction`: Select files or folders in your project, trigger this action, and specify output - settings to compile documentation. -- **Code Comments Actions** - - `CommentsAction`: Highlight a code block and activate this action to automatically add comments explaining the - code. - - `DescribeAction`: Use this action to generate a detailed description of the selected code, enhancing its - documentation. -- **Code Generation Actions** - - `InternalCoderAction`: Start a coding session with this action to receive coding assistance directly in the IDE. - - `WebDevAction`: Trigger this action for AI-powered assistance with web development tasks, including code - generation and architecture suggestions. - - `AutoDevAction`: Automates development tasks by translating user directives into actionable development tasks and code modifications. -- **Markdown Enhancement Actions** - - `MarkdownImplementActionGroup`: In a Markdown file, select text and use this action to generate code snippets in - various languages. - - `MarkdownListAction`: Highlight a list in your Markdown file and activate this action to automatically generate - and insert new list items. -- **Development Workflow Actions** - - `RecentCodeEditsAction`: Access this action to see a list of your most recent code edits and quickly reapply any - of them. - - `RedoLast`: Use this action to redo the last AI Coder action you executed, enhancing your workflow efficiency. -- **Text Transformation Actions** - - `AppendAction`: Select text and trigger this action to append AI-generated text, expanding on your initial - selection. - - `ReplaceOptionsAction`: Highlight text and activate this action to receive and choose from AI-generated text - options for replacement. - -Each action is designed to seamlessly integrate into your development workflow, offering a range of enhancements from -code editing to documentation and AI integration. Explore these actions to discover how they can improve your -productivity and coding experience in IntelliJ IDEA. - -# code\CustomEditAction.kt - -## CustomEditAction Documentation - -### Overview - -The `CustomEditAction` class extends the functionality of `SelectionAction` to provide a mechanism for editing code -based on user instructions. It leverages a virtual API to process the code modifications, which can include operations -like adding comments, refactoring, or any other code transformation specified by the user. This action is designed to -integrate with an IDE environment, allowing users to easily modify their code using natural language instructions. - -### Key Components - -#### VirtualAPI Interface - -- **Purpose**: Defines the contract for the code editing service. -- **Methods**: - - `editCode(code: String, operation: String, computerLanguage: String, humanLanguage: String)`: Takes the original - code, an operation in natural language, the programming language of the code, and the human language of the - operation. Returns an `EditedText` object containing the modified code. - -- **EditedText Data Class**: - - Holds the result of the code editing operation, including the modified code and its language. - -#### CustomEditAction Class - -- **Functionality**: Allows users to input natural language instructions to edit selected code within an IDE. -- **Key Methods**: - - `getConfig(project: Project?)`: Displays a dialog to the user to input the editing instruction. - - `processSelection(state: SelectionState, instruction: String?)`: Processes the user's instruction on the selected - code and returns the edited code. - -#### Proxy Property - -- **Purpose**: Creates an instance of the `VirtualAPI` using a `ChatProxy`, pre-configured with examples and settings - from `AppSettingsState`. -- **Functionality**: It demonstrates how to use the virtual API by adding an example of code editing and then creates - the proxy instance that will be used for actual code editing operations. - -### Usage - -1. **Invoke CustomEditAction**: This action can be triggered within an IDE environment where it is integrated. -2. **Input Instruction**: When prompted, the user inputs a natural language instruction detailing how the selected code - should be edited. -3. **Code Transformation**: The action processes the instruction and applies the specified edits to the selected code. - -### Integration Points - -- **AppSettingsState**: Utilizes application settings for configuring the chat proxy, including the model to use and the - temperature setting for the AI's responses. -- **UITools**: Used for displaying the input dialog to the user. - -### Example - -If a user selects a piece of code and inputs the instruction "Add code comments explaining the -function", `CustomEditAction` will process this instruction, potentially resulting in the selected code being annotated -with comments that explain its functionality, based on the capabilities of the underlying virtual API. - -### Conclusion - -`CustomEditAction` provides a powerful and intuitive way for developers to edit and refactor their code using natural -language instructions, seamlessly integrating AI-powered code transformation into their development workflow. - -# code\CommentsAction.kt - -#### CommentsAction Class Documentation - -The `CommentsAction` class is part of the AI Coder extension, designed to enhance code readability by automatically -adding comments to the selected code block within your IDE. This class extends the functionality -of `SelectionAction`, allowing it to process selected text and utilize AI services to generate insightful -comments. - -##### Features - -- **Language Support**: The action is designed to work with a variety of programming languages, excluding plain text. It - ensures that the feature is only applied to code, where commenting is beneficial. -- **AI-Powered**: Utilizes the `ChatProxy` class to communicate with an AI model, specifically tailored to generate - comments for code. This integration allows for context-aware, meaningful comments that improve code understanding. -- **Customizable**: Leverages settings from `AppSettingsState` to allow customization of the AI's behavior, including - the model's temperature and the choice of language model, adapting the comments to the user's preferences. - -##### Key Methods - -- **getConfig(Project?): String**: Returns a configuration string for the action. Currently, this method returns an - empty string, serving as a placeholder for future configurations. - -- **isLanguageSupported(ComputerLanguage?): Boolean**: Checks if the given programming language is supported by the - action. It returns `true` for all programming languages except for plain text, ensuring the action is applied to - actual code. - -- **processSelection(SelectionState, String?): String**: The core method of the class, it takes the selected code block - and processes it through the AI model to generate and insert comments. It utilizes the `ChatProxy` class to - communicate with the AI, passing parameters such as the selected text, desired operations, and language settings. - -##### CommentsAction_VirtualAPI Interface - -An interface defining the `editCode` method, which is essential for the interaction with the AI model to edit and -comment on the code. It specifies the parameters required for the operation, including the code block, operation -description, computer language, and human language. - -##### CommentsAction_ConvertedText Class - -A nested class within the `CommentsAction_VirtualAPI` interface, designed to encapsulate the result of the AI's code -commenting process. It contains fields for the commented code (`code`) and the language of the code (`language`), -facilitating easy integration and use of the AI-generated comments within the IDE. - -#### Usage - -To use the `CommentsAction` feature, ensure your IDE project is set up with the AI Coder extension and configured -according to your preferences in `AppSettingsState`. Select a block of code in a supported language, and trigger -the `CommentsAction`. The AI will analyze the selected code and insert comments, enhancing the code's readability and -maintainability. - -This documentation provides a concise overview of the `CommentsAction` class and its functionalities. For further -details or customization options, refer to the source code or extension documentation. - -# code\DocAction.kt - -## DocAction Documentation - -### Overview - -`DocAction` is a specialized action within the AI Coder plugin designed to automatically generate documentation for -selected code blocks within your project. It leverages a virtual API and a chat model to process and convert code into -well-documented text, enhancing readability and maintainability. - -### Key Components - -#### DocAction_VirtualAPI - -An interface that defines the method `processCode`, which takes a code snippet and other parameters to return -a `DocAction_ConvertedText` object containing the generated documentation text and its language. - -##### DocAction_ConvertedText - -A class that holds the resulting documentation text (`text`) and the language of the documentation (`language`). - -#### Proxy Initialization - -Upon instantiation, `DocAction` initializes a `ChatProxy` with a predefined example to guide the documentation -generation process. This setup involves specifying the operation (e.g., "Write detailed KDoc prefix for code block"), -the code language, and the target human language. - -### Functionality - -#### processSelection - -When a code selection is made, `processSelection` is invoked to generate documentation for the selected code block. It -formats the selected text, calls the `processCode` method through the proxy, and prepends the generated documentation to -the original code. - -#### isLanguageSupported - -Determines if the selected code's language is supported for documentation generation, based on the presence and -non-emptiness of the `docStyle` attribute in the `ComputerLanguage` object. - -#### editSelection - -Adjusts the selection range to encompass the entire code block identified by the PSI (Program Structure Interface) tree, -ensuring that the documentation is generated for the complete logical code block. - -### Usage - -To use `DocAction`, simply select a code block within your project and activate the action. The plugin will -automatically generate and insert the appropriate documentation based on the code's context, language, and specified -documentation style. - -### Configuration - -`DocAction` relies on the `AppSettingsState` for configuration, including the default chat model, temperature for the -chat model's responses, and the target human language for the documentation. - -### Limitations - -- The action does not support plain text (`ComputerLanguage.Text`) or languages without a defined documentation - style (`docStyle`). -- The quality and accuracy of the generated documentation may vary based on the complexity of the code and the - effectiveness of the provided examples to the chat model. - -### Conclusion - -`DocAction` enhances the development experience by automating the documentation process, making code easier to -understand and maintain. By integrating advanced AI models, it offers a sophisticated approach to code documentation, -tailored to the developers' needs. - -# code\ImplementStubAction.kt - -## ImplementStubAction Documentation - -### Overview - -The `ImplementStubAction` class is part of a larger framework designed to enhance coding efficiency by automating -certain tasks. This specific action focuses on assisting developers in implementing stubs—placeholders for -functionalities yet to be developed—by leveraging AI-powered code editing capabilities. - -### Key Features - -- **Language Support**: Not all programming languages are supported. The action excludes plain - text (`ComputerLanguage.Text`) but supports a variety of other programming languages. -- **Automatic Selection**: It automatically selects the smallest code range that matches a code element within the - editor's current state, providing a default selection for operation. -- **AI-Powered Code Editing**: Utilizes a virtual API to communicate with an AI model, editing code based on the - operation "Implement Stub". This process considers both the computer and human languages set in the application - settings. - -### How It Works - -1. **Language Check**: Initially, it checks if the programming language of the code is supported, excluding plain text. -2. **Selection Identification**: It identifies the optimal code selection for the operation by finding the smallest code - range that matches a code element. -3. **Code Processing**: The selected code is processed to remove any suffixes and trimmed. This processed code is then - sent to the AI-powered virtual API. -4. **AI Interaction**: Through the `VirtualAPI`, the action sends the code, operation type ("Implement Stub"), computer - language, and human language to an AI model for processing. -5. **Result**: The AI model returns the edited code, which is then provided as the action's output. - -### VirtualAPI - -An interface within the `ImplementStubAction` class, `VirtualAPI` is crucial for the AI interaction. It defines the -method `editCode` for sending code to the AI model and receiving the edited code. The `ConvertedText` inner class is -used to encapsulate the result, containing the edited code and its language. - -### Usage - -This action is designed to be integrated into a larger system, likely an IDE plugin, where it can be triggered in the -context of editing code. Users do not interact with this action directly but benefit from its functionality during their -development workflow, particularly when implementing stubs or placeholders in their codebase. - -### Configuration - -The action requires minimal configuration, primarily relying on the application's settings for determining the human and -computer languages. The `AppSettingsState` singleton is used to fetch these settings, including the AI model's -temperature setting for processing. - -### Conclusion - -The `ImplementStubAction` enhances coding efficiency by automating the implementation of stubs through AI-powered code -editing. It supports various programming languages, automatically identifies the optimal code selection, and leverages a -virtual API for AI interaction, streamlining the development process. - -# code\PasteAction.kt - -## PasteAction Documentation - -### Overview - -The `PasteAction` class is designed to enhance the functionality of pasting text within the IDE. It automatically -converts the text from the clipboard into a specified programming language, leveraging a virtual API for the conversion -process. This feature is particularly useful for developers working with multiple programming languages or needing to -integrate code snippets from various sources seamlessly. - -### Features - -- **Automatic Language Detection:** The action can automatically detect the source language of the text in the - clipboard. -- **Language Conversion:** Converts the clipboard text to the target programming language as specified by the user's - current context or selection. -- **Clipboard Support:** Efficiently handles text from the clipboard, supporting both plain text and Unicode text - flavors. -- **Language Support Check:** Ensures that the action is only available for supported programming languages, excluding - plain text. - -### Usage - -1. **Clipboard Preparation:** Ensure that the text you wish to convert is copied to your system's clipboard. -2. **Triggering PasteAction:** Use the designated shortcut or menu option to trigger the `PasteAction` within your IDE. -3. **Automatic Conversion:** The action automatically detects the language of the text in the clipboard, converts it to - the target language, and pastes it into your current editor window. - -### Requirements - -- The action requires access to a virtual API (`VirtualAPI`) for converting the text between languages. -- The IDE should have access to the `AppSettingsState` configuration for default model and temperature settings used - during conversion. - -### Limitations - -- The action does not support plain text (`ComputerLanguage.Text`) as a target language for conversion. -- The functionality is dependent on the availability and response of the `VirtualAPI`. - -### API Reference - -#### VirtualAPI - -An interface used for converting text between different programming languages. - -##### Methods - -- `convert(text: String, from_language: String, to_language: String): ConvertedText` - Converts the given text from one - language to another. - -##### Inner Class - -- `ConvertedText` - Holds the result of a conversion, including the converted code and its language. - -### Troubleshooting - -- **Conversion Not Triggering:** Ensure that the clipboard contains text and that the text is in a supported format ( - plain text or Unicode text). -- **Unsupported Language Error:** Check if the target language is supported and not marked as plain text. - -For further assistance, refer to the developer documentation or contact support. - -# code\DescribeAction.kt - -## DescribeAction Documentation - -### Overview - -The `DescribeAction` class is part of a larger system designed to enhance coding efficiency by automatically generating -descriptions for code snippets. This functionality is particularly useful within the context of an IDE (Integrated -Development Environment), where understanding and documenting code can significantly improve readability and -maintainability. - -### Key Components - -#### DescribeAction_VirtualAPI - -This interface defines the core functionality for describing code. It includes a single method, `describeCode`, which -takes a code snippet, the programming language of the code, and the desired language for the description. It returns an -instance of `DescribeAction_ConvertedText`, which contains the generated description. - -##### DescribeAction_ConvertedText - -A simple data class that holds the result of the code description process. It has two properties: `text`, which is the -generated description of the code, and `language`, indicating the language used for the description. - -#### DescribeAction Class - -Extends `SelectionAction` and utilizes the `DescribeAction_VirtualAPI` to generate descriptions for selected -code snippets within the IDE. - -##### Key Methods - -- `getConfig(project: Project?)`: Returns a configuration string for the action. Currently, this method returns an empty - string. - -- `processSelection(state: SelectionState, config: String?)`: Takes the current selection state and configuration, - generates a description for the selected code, and formats it according to the code's comment style. The result is a - string that combines the generated description with the original code, properly indented and commented. - -#### Proxy Initialization - -The `proxy` property lazily initializes an instance of `DescribeAction_VirtualAPI` using the `ChatProxy` class. This -setup allows for dynamic interaction with a backend service capable of generating code descriptions. The configuration -for this proxy includes settings for the AI model, temperature, and the number of retries for deserialization. - -### Usage - -To use `DescribeAction`, a user would typically select a portion of code within their IDE. The action then triggers -the `processSelection` method, which communicates with the backend service to generate a description for the selected -code. The description is formatted according to the code's comment style and inserted above the selected code snippet, -providing immediate, in-context documentation. - -### Configuration - -The behavior of `DescribeAction` can be influenced by settings in `AppSettingsState`, such as the desired human language -for descriptions, the AI model used for generating descriptions, and the temperature setting for the AI's responses. - -### Conclusion - -`DescribeAction` offers a convenient way to automatically generate descriptions for code snippets, facilitating better -documentation and understanding of code within projects. By leveraging AI through a backend service, it provides -accurate and context-aware descriptions, enhancing the development workflow. - -# code\InsertImplementationAction.kt - -## Insert Implementation Action Documentation - -### Overview - -The `InsertImplementationAction` class is part of a code generation tool designed to automatically insert code -implementations into your project. It leverages AI to generate code based on a given specification, which can be derived -from comments or selected text within your code editor. This action is integrated into an IDE environment, providing a -seamless experience for generating and inserting code. - -### Key Features - -- **AI-Powered Code Generation**: Utilizes an AI model to generate code implementations based on natural language - specifications. -- **Support for Multiple Languages**: Capable of generating code for various programming languages, excluding Text and - Markdown. -- **Context-Aware**: Takes into account the surrounding context of the selected text or comment to generate relevant - code. -- **Customizable**: Leverages project-specific settings for human and computer languages, as well as AI model - configurations. - -### How It Works - -1. **Selection**: The action can be triggered on a specific selection within your code editor. This selection can either - be a comment or a block of code. -2. **Specification Extraction**: The tool extracts a specification from the selected text or the largest intersecting - comment. This specification is then used as input for the AI model. -3. **AI Code Generation**: The extracted specification, along with contextual information about the surrounding code, is - sent to an AI model. The model generates a code implementation based on this input. -4. **Insertion**: The generated code is automatically inserted into your codebase, directly following the selected text - or comment. - -### Usage - -To use the `InsertImplementationAction`, follow these steps: - -1. **Select Text or Comment**: In your code editor, select a block of text or a comment that describes the functionality - you wish to implement. -2. **Trigger Action**: Trigger the `InsertImplementationAction` through your IDE's action or shortcut mechanism. -3. **Review and Save**: The generated code will be inserted automatically. Review the inserted code and make any - necessary adjustments before saving your file. - -### Requirements - -- The action requires an IDE environment that supports the integration of custom actions. -- A configured AI model and API key are necessary for code generation. These can be set up in the project's settings. - -### Supported Languages - -The `InsertImplementationAction` supports various programming languages for code generation. However, it does not -support generating code for Text or Markdown files. - -### Configuration - -Project-specific configurations, such as the preferred human and computer languages and AI model settings, can be -adjusted in the project's settings. These settings influence the behavior of the code generation process. - -### Conclusion - -The `InsertImplementationAction` offers a powerful way to accelerate the development process by automatically generating -and inserting code implementations. By leveraging AI and understanding the context of your project, it provides relevant -and customizable code snippets, enhancing productivity and code quality. - -# code\RecentCodeEditsAction.kt - -## Recent Code Edits Action - -### Overview - -The `RecentCodeEditsAction` is an IntelliJ IDEA plugin component that provides users with a dynamic action group listing -their most recent custom code edits. This feature enhances the development environment by allowing quick access and -reapplication of frequently used custom edits, streamlining the coding process. - -### Features - -- **Dynamic Listing**: Displays a list of the most recent custom code edits as individual actions. -- **Quick Access**: Enables users to quickly reapply a recent edit from the list. -- **Visibility Control**: The action group is only visible and enabled when applicable, ensuring a clutter-free - environment. - -### Usage - -#### Activation Conditions - -- The action group becomes visible and enabled only when there is a selection in the editor, and the current file is - recognized as a programming language file (not plain text). -- It is context-sensitive and tailored to enhance productivity by providing relevant actions based on the user's recent - activities. - -#### Accessing Recent Edits - -1. **Selection Requirement**: Ensure that you have selected a portion of code in your editor. The action group is - context-sensitive and requires a selection to operate. -2. **Navigate to Action**: Access the `RecentCodeEditsAction` from the designated menu or action search in IntelliJ - IDEA. -3. **Choose an Edit**: A list of recent custom edits will be displayed, each prefixed with a number for easy - identification. If the list contains fewer than ten items, they will be prefixed with an underscore and the item - number (e.g., `_1: YourRecentEdit`). For ten or more items, they will be listed simply with the number ( - e.g., `10: YourRecentEdit`). -4. **Apply an Edit**: Click on the desired edit to apply it to the current selection. - -### Customization - -The actions listed are dynamically generated based on the user's recent custom code edits, ensuring that the most -relevant and frequently used edits are easily accessible. This list is managed through the `AppSettingsState` -configuration, where the history of commands is maintained. - -### Limitations - -- The action group is not available for plain text files, as it is designed to support programming languages recognized - by IntelliJ IDEA. -- The visibility and availability of the action group depend on the current context, specifically requiring a text - selection within the editor. - -### Conclusion - -The `RecentCodeEditsAction` enhances the IntelliJ IDEA development environment by providing a streamlined way to access -and reapply frequently used custom code edits. By integrating this feature, developers can significantly reduce the time -spent on repetitive coding tasks, focusing more on creative and complex aspects of their projects. - -# code\RenameVariablesAction.kt - -## Rename Variables Action Documentation - -### Overview - -The `RenameVariablesAction` class is an extension of the `SelectionAction` class designed to facilitate the renaming of -variables in code. It leverages an AI-based suggestion system to propose new names for variables, aiming to improve code -readability and maintainability. - -### Key Components - -#### RenameAPI Interface - -- **Purpose**: Defines the contract for suggesting new names for variables. -- **Method**: `suggestRenames(code: String, computerLanguage: String, humanLanguage: String)`: Accepts the current code - snippet, the programming language of the code, and the human language for the suggestions. It returns - a `SuggestionResponse` containing a list of suggested renames. - -#### SuggestionResponse Class - -- **Purpose**: Encapsulates the response from the rename suggestion API. -- **Attributes**: - - `suggestions`: A mutable list of `Suggestion` objects. - -#### Suggestion Class - -- **Purpose**: Represents a single rename suggestion. -- **Attributes**: - - `originalName`: The original variable name. - - `suggestedName`: The suggested new name for the variable. - -### Usage - -1. **Initialization**: The `RenameVariablesAction` class is instantiated as part of the plugin's action system. -2. **Configuration**: Override the `getConfig` method if you need to provide specific configurations for the action. By - default, it returns an empty string. -3. **Processing Selection**: The `processSelection` method is the core of the action. It: - - Retrieves rename suggestions for the selected text in the code editor. - - Displays a dialog for the user to choose which suggestions to apply. - - Applies the selected renames to the text. -4. **Choosing Suggestions**: The `choose` method displays a checkbox dialog with the suggested renames, allowing users - to select which renames to apply. - -### Supported Languages - -The action supports all programming languages except plain text (`ComputerLanguage.Text`). The support is determined by -the `isLanguageSupported` method. - -### Integration - -This action is designed to be integrated into the IntelliJ IDEA platform. It utilizes the platform's action system and -UI tools for displaying dialogs and processing text selections. - -### Example - -When a user selects a block of code and triggers the `RenameVariablesAction`, the action will: - -- Analyze the selected code to identify variable names. -- Use the `RenameAPI` to get suggestions for renaming these variables based on the code's and user's language. -- Present the user with a dialog to select which variables to rename. -- Apply the selected renames to the code. - -This action streamlines the process of renaming variables, making code more readable and maintainable with minimal -effort from the user. - -# dev\AppServer.kt - -## AppServer Documentation - -### Overview - -The `AppServer` class is a core component designed to manage and serve web applications within a development -environment. It facilitates the dynamic addition of applications, handling their web contexts, and managing a web server -instance. This class is particularly useful for projects that require running and testing multiple web applications -simultaneously. - -### Features - -- **Dynamic Application Management:** Allows adding and removing web applications dynamically without needing to restart - the server manually. -- **WebSocket Support:** Integrated support for WebSocket applications, enabling real-time bi-directional communication - between clients and the server. -- **Progress Monitoring:** Includes functionality to monitor the server's running state and gracefully handle shutdowns - or restarts. - -### Key Components - -- **Server Instance:** A Jetty server instance configured to listen on a specified port and address. -- **Application Registry:** A registry for managing the active web applications (ChatServer instances) and their paths. -- **Web Context Management:** Handles the creation and configuration of web contexts for each registered application. - -### Usage - -#### Starting the Server - -To start the server, simply call the `start()` method. This initializes the server (if not already running) and begins -listening for incoming connections on the configured port and address. - -```kotlin -val project: Project? = // Obtain your IntelliJ Project instance -val appServer = AppServer("localhost", 8080, project) -appServer.start() -``` - -#### Adding Applications - -Applications can be added dynamically using the `addApp(path: String, socketServer: ChatServer)` method. This method -registers the application and its web context, making it accessible at the specified path. - -```kotlin -val chatServer = ChatServer() // Your ChatServer instance -appServer.addApp("/chat", chatServer) -``` - -#### Stopping the Server - -To stop the server, call the `stop()` method. This method stops the server and clears any registered applications, -preparing the server for a clean shutdown. - -```kotlin -AppServer.stop() -``` - -### Singleton Access - -The `AppServer` class provides a singleton access pattern through its companion object, allowing for easy management of -a single server instance across the application. - -- **Get Server:** `AppServer.getServer(project: Project?)` returns the current server instance, starting it if - necessary. -- **Stop Server:** `AppServer.stop()` stops the current server instance and clears it. - -### Important Considerations - -- The server automatically restarts upon adding a new application to reflect the updated context. Ensure that this - behavior is accounted for in your application logic. -- The server uses lazy initialization for performance optimization and to avoid unnecessary resource allocation. - -### Conclusion - -The `AppServer` class offers a flexible and efficient way to manage web applications and their server contexts within a -development environment. Its dynamic application management, WebSocket support, and progress monitoring capabilities -make it a valuable tool for developers working on web-based projects. - -# dev\PrintTreeAction.kt - -## PrintTreeAction User Guide - -### Overview - -The `PrintTreeAction` is a powerful tool integrated into the IntelliJ IDE, designed for developers who need to visualize -the structure of their code files in a tree format. This action is particularly useful for understanding the -organization and hierarchy of classes, methods, and other elements within a file. - -### Prerequisites - -Before you can use the `PrintTreeAction`, ensure the following: - -- You have IntelliJ IDE installed. -- The "devActions" setting is enabled in your project's `AppSettingsState`. - -### How to Use PrintTreeAction - -1. **Open the Desired File**: Navigate to and open the file you wish to analyze in IntelliJ. -2. **Access the Action**: Right-click within the editor window to open the context menu. Look for the "PrintTreeAction" - option. If you do not see this option, ensure you have met all prerequisites. -3. **Execute the Action**: Click on "PrintTreeAction". The action will process the currently open file. -4. **View the Results**: The tree structure of the file will be printed to the IntelliJ log. You can access this log at - the bottom of the IntelliJ window, typically in the "Run" or "Debug" tabs. - -### Features - -- **Tree Structure Visualization**: Quickly understand the hierarchical structure of your PsiFile, including classes, - methods, and other code elements. -- **Easy Access**: Available directly from the editor's context menu, allowing for seamless integration into your - development workflow. -- **Conditional Availability**: This action is only available when the "devActions" setting is enabled, preventing - accidental usage in non-development environments. - -### Troubleshooting - -- **Action Not Visible**: If the "PrintTreeAction" is not visible in the context menu, ensure that the "devActions" - setting is enabled in your `AppSettingsState`. -- **Null Pointer Exceptions**: Ensure the file you are trying to analyze is fully loaded and not corrupted to avoid null - pointer exceptions during the action's execution. - -### Conclusion - -The `PrintTreeAction` is an invaluable tool for developers looking to gain insights into the structure of their code -files. By following the steps outlined in this guide, you can efficiently utilize this action to enhance your -development process within the IntelliJ IDE. - -# FileContextAction.kt - -## FileContextAction Documentation - -### Overview - -`FileContextAction` is an abstract class designed to extend the functionality of actions within a specific file or -folder context in an IntelliJ platform-based IDE. It allows developers to create actions that can process selected files -or folders, perform operations based on those selections, and integrate seamlessly with the IDE's UI and file system. - -### Key Features - -- **Flexible File and Folder Support**: Actions can be configured to support either files, folders, or both, depending - on the needs of the specific action being implemented. -- **Configurable Processing**: Implementers can define custom processing logic for selected files or folders, allowing - for a wide range of operations such as file generation, modification, or analysis. -- **IDE Integration**: Utilizes the IntelliJ platform's UI and file system APIs for selecting files/folders, displaying - notifications, and managing file operations within the IDE environment. -- **Asynchronous Execution**: Operations are performed in a separate thread, ensuring that the IDE remains responsive - during potentially time-consuming file processing tasks. - -### Usage - -To use `FileContextAction`, you need to create a subclass and implement the abstract methods. Here's a simplified -example: - -```kotlin -class MyFileAction : FileContextAction() { - override fun processSelection(state: SelectionState, config: MyConfig?): Array { - // Implement your file processing logic here - return arrayOf() // Return an array of files that were processed or generated - } - - override fun getConfig(project: Project?, e: AnActionEvent): MyConfig? { - // Optionally, provide configuration for the action based on the project or event context - return MyConfig() - } -} -``` - -#### Implementing `processSelection` - -This method is where the main logic of your action should be implemented. It receives a `SelectionState` object -containing the selected file or folder and the project root directory. You can use this information to perform your -desired file operations. - -#### Configuring Your Action - -The `getConfig` method allows you to provide custom configuration for your action, which can be useful for tailoring its -behavior based on the project context or user preferences. - -### Integration Points - -- **isEnabled**: Determines whether the action is enabled based on the current context, such as the type of file - selected or project settings. -- **handle**: The entry point for the action's execution. It sets up the necessary context and invokes - the `processSelection` method. - -### Best Practices - -- Ensure that your file operations are efficient and handle potential errors gracefully to avoid disrupting the user's - workflow. -- Use the provided IDE APIs for UI interactions and file system operations to ensure compatibility and a consistent user - experience. - -### Conclusion - -`FileContextAction` provides a powerful framework for extending the functionality of IntelliJ platform-based IDEs with -custom file and folder actions. By implementing the abstract methods and following the best practices, developers can -create sophisticated tools that enhance the development experience. - -# dev\InternalCoderAction.kt - -## InternalCoderAction Documentation - -### Overview - -The `InternalCoderAction` class is part of a plugin designed to integrate coding assistance directly into the IntelliJ -IDE. It facilitates the creation of a coding session within the IDE, leveraging an internal coding agent to provide -suggestions and enhancements to the user's coding experience. This action is triggered through the IDE's action system -and is intended for developers looking for an integrated coding assistant. - -### Features - -- **Session Initialization**: Creates a unique session for each coding instance, ensuring personalized and isolated - coding assistance. -- **Dynamic Symbol Resolution**: Collects and resolves symbols from the current editor context, including the editor, - file, element, and project, to provide context-aware coding assistance. -- **Coding Agent Integration**: Utilizes a `CodingAgent` to process coding requests and provide suggestions based on the - current context and user input. -- **Web UI Support**: Opens a browser window pointing to the coding session's UI, allowing for an interactive coding - assistance experience. -- **Customizable Assistance**: Supports customization of the coding agent's behavior, including the response temperature - and operational details. - -### Usage - -1. **Prerequisites**: Ensure that the plugin is installed and enabled in your IntelliJ IDE. The feature is available - only if the development actions are enabled in the application settings (`AppSettingsState.instance.devActions`). - -2. **Triggering the Action**: The action can be triggered through the IDE's action system, typically via a menu item or - keyboard shortcut specific to the plugin. - -3. **Coding Session**: Once triggered, the action initializes a new coding session, setting up the necessary environment - and context for the coding agent to operate. - -4. **Interaction**: Interact with the coding agent through the opened web UI or directly within the IDE, depending on - the implementation details of the plugin. - -5. **Session Closure**: The session remains active until manually closed or terminated by the user or the system. - -### Configuration - -- **Development Actions**: Enable or disable development actions through the `AppSettingsState` configuration. -- **Session Parameters**: Customize session parameters such as the response temperature and operational details directly - within the `InternalCoderAction` class or through external configuration options. - -### Troubleshooting - -- **Browser Opening Failure**: If the system encounters an issue opening the browser automatically, check the system's - default browser settings and ensure that the IDE has the necessary permissions. -- **Session Initialization Error**: Ensure that the plugin's server component (`AppServer`) is running and accessible. - Check the IDE's log files for any error messages related to the plugin. - -### Conclusion - -The `InternalCoderAction` provides a seamless integration of coding assistance within the IntelliJ IDE, enhancing the -development experience through context-aware suggestions and interactive coding sessions. By leveraging advanced coding -agents and a dedicated UI, developers can improve their coding efficiency and quality directly within their preferred -development environment. - -# generic\AppendAction.kt - -## AppendAction Documentation - -### Overview - -The `AppendAction` class is a specialized action designed to append text to the end of a user's selected text within an -IDE environment. It leverages OpenAI's language model to generate contextually relevant text based on the user's -selection. - -### How It Works - -1. **Configuration Retrieval**: Initially, the action retrieves any necessary configuration from the project settings, - though in its current implementation, it returns an empty string as it does not require specific configuration. - -2. **Processing Selection**: The core functionality resides in the `processSelection` method, where it performs the - following steps: - - Retrieves the application's settings, particularly focusing on the default chat model and temperature settings for - the OpenAI API request. - - Constructs a `ChatRequest` object with the model and temperature settings, and includes two messages: - - A system message indicating the action to be performed ("Append text to the end of the user's prompt"). - - A user message containing the selected text. - - Sends the request to the OpenAI API and receives a chat response. - - Appends the generated text to the original selected text, ensuring no duplication of the initial selection. - -### Requirements - -- **IntelliJ Platform**: This action is designed to work within the IntelliJ platform, requiring a project context to - operate. -- **AppSettingsState**: The action depends on `AppSettingsState` for retrieving application-wide settings, such as the - default chat model and temperature for API requests. - -### Usage - -To use the `AppendAction`, ensure it is properly integrated into your IntelliJ platform-based application or plugin. It -does not require manual configuration but relies on the application's settings for the OpenAI API parameters. - -When triggered, it will automatically append contextually generated text to the user's selected text, enhancing or -completing their input based on the model's understanding and the provided prompt. - -### Limitations - -- **Configuration**: Currently, the `getConfig` method does not utilize project-specific configurations and returns an - empty string. -- **Context Sensitivity**: The effectiveness of the appended text depends on the accuracy of the OpenAI model's - understanding of the selected text and the provided prompt. - -### Conclusion - -The `AppendAction` offers a convenient way to extend user input with AI-generated text, seamlessly integrating with the -IntelliJ platform. By leveraging OpenAI's language models, it provides a powerful tool for enhancing user productivity -and creativity within the development environment. - -# generic\AnalogueFileAction.kt - -## Analogue File Action Documentation - -### Overview - -The Analogue File Action is a feature designed for IntelliJ-based IDEs that assists developers in automatically -generating new files based on existing ones, with modifications guided by user-provided directives. This action -leverages the power of AI to interpret directives and apply them to the selected file, creating a new, analogous file -that meets the specified requirements. - -### Features - -- **Context-Sensitive Activation**: The action is only enabled for non-directory files, ensuring it is contextually - relevant. -- **Customizable Directives**: Users can input natural language directives to guide the creation of the new file. -- **AI-Powered Processing**: Utilizes an AI model to interpret directives and generate the new file content. -- **Automatic File Naming and Placement**: Generates a unique file name and path to avoid conflicts, placing the new - file relative to the project root. -- **IDE Integration**: Automatically opens the newly created file in the IDE for immediate review and editing. - -### How to Use - -1. **Select a File**: In your project, select the file you want to base your new file on. -2. **Activate the Action**: Right-click and find the "Create Analogue File" option. This option is only available for - non-directory files. -3. **Enter Directive**: In the popup dialog, enter your directive in the provided text area. This directive should - describe how you want the new file to differ from the selected one. -4. **Generate File**: Click "OK" to generate the new file. The AI will process your directive, create the new file, and - place it in an appropriate location within your project structure. -5. **Review and Edit**: The new file will automatically open in your IDE. Review the generated content and make any - necessary adjustments. - -### Settings - -- **Directive**: A JTextArea where you input your natural language instructions for generating the new file. - -### Technical Details - -- **Settings Storage**: User settings, including the directive, are stored in a `UserSettings` class instance. -- **File Generation**: The `generateFile` method processes the base file and directive, interacting with an AI model to - produce the new file content and path. -- **File Handling**: The action ensures the new file does not overwrite existing files by checking for conflicts and - adjusting the file name as necessary. -- **IDE Integration**: Utilizes IntelliJ platform APIs for file operations and UI interactions, ensuring a seamless - experience within the IDE. - -### Requirements - -- IntelliJ-based IDE (e.g., IntelliJ IDEA, PyCharm) -- Java Development Kit (JDK) - -### Installation - -This feature is packaged as part of a specific IntelliJ plugin. Install the plugin from the JetBrains Marketplace or -your IDE's plugin settings panel. - -### Support - -For issues, feature requests, or contributions, please refer to the project's GitHub repository or contact the -development team through the appropriate channels. - -# generic\AutoDevAction.kt - -## AutoDevAction Documentation - -### Overview - -The `AutoDevAction` class is part of a system designed to automate development tasks within a project. It integrates -with an IDE to provide a user-friendly interface for automating code modifications, leveraging AI models to interpret -user requests and generate actionable development tasks. - -### Key Features - -- **Automated Task Generation**: Translates user directives into a detailed action plan, breaking down requests into - manageable tasks. -- **Code Modification Suggestions**: Generates code patches in diff format, suggesting specific changes to be made in - the project files. -- **Interactive Web UI**: Opens a browser window to interact with the user, providing a session-based interface for task - management and execution. -- **Integration with AI Models**: Utilizes GPT models for understanding user requests and generating code modifications. - -### Usage - -1. **Initialization**: The action is triggered within an IDE environment, starting a new session for the user. -2. **Selecting a Project Folder**: The user selects a folder within their project. This folder's path is stored and - associated with the current session. -3. **Web UI Interaction**: A browser window is opened, directing the user to an interactive session where they can input - their development requests. -4. **Task Generation and Execution**: The system interprets the user's requests, generating a list of tasks and - suggesting code modifications to fulfill these tasks. The user can review and apply these suggestions directly from - the web UI. - -### Components - -#### AutoDevApp - -Represents the application server handling user sessions and messages. It processes user messages to generate -development tasks and code modification suggestions. - -##### Key Methods - -- `userMessage()`: Handles incoming messages from users, generating tasks and code modifications based on the content of - the message. - -#### AutoDevAgent - -Responsible for processing individual development tasks, interacting with AI models to generate code patches and -suggestions. - -##### Key Methods - -- `start()`: Initiates the process of generating development tasks and code modifications based on the user's request. - -### How It Works - -1. The `AutoDevAction` class initiates a session and opens a web UI for user interaction. -2. The user inputs a development request in the web UI. -3. The `AutoDevApp` processes this request, utilizing `AutoDevAgent` to interact with AI models and generate a list of - actionable tasks. -4. For each task, `AutoDevAgent` suggests specific code modifications in diff format. -5. The user reviews and applies these suggestions to their project files directly from the web UI. - -### Prerequisites - -- An IDE environment compatible with the system. -- Access to the web UI through a supported browser. - -### Conclusion - -The `AutoDevAction` system offers a powerful tool for automating development tasks, leveraging AI to streamline the -process of code modification. By providing a user-friendly interface and integrating with advanced AI models, it -simplifies the task management process, making it easier for developers to implement changes and enhancements to their -projects. - -# generic\CreateFileAction.kt - -## CreateFileAction Documentation - -### Overview - -The `CreateFileAction` class is designed to automate the process of generating and creating new files within a project -based on natural language directives. It leverages the OpenAI API to interpret these directives and generate the -corresponding file content and path. This action is part of a larger system aimed at enhancing developer productivity -through automation. - -### How It Works - -1. **Directive Input**: The user provides a natural language directive describing the file to be created. This can be as - simple as "Create a default log4j configuration file" or more complex, depending on the needs. - -2. **File Generation**: Based on the provided directive, the system uses the OpenAI API to generate both the content of - the file and the suggested file path relative to the project root. - -3. **File Creation**: The system then creates the file at the suggested path with the generated content. If a file with - the same name already exists, it appends a unique index to the file name to avoid overwriting. - -### Key Components - -- **ProjectFile**: A simple data class holding the path and code of the generated file. -- **SettingsUI**: A user interface component that allows the user to input the directive in a text area. -- **Settings**: Holds the directive as a string for processing. -- **processSelection**: The main function that processes the user's selection and directive, generating and creating the - file accordingly. - -### Usage - -1. **Input Directive**: Through the `SettingsUI`, the user inputs a directive describing the file they wish to create. -2. **Selection**: The user selects a file or directory within their project, which serves as a context for the file - generation. -3. **Execution**: Upon executing the action, the system processes the directive and selection, generating and creating - the new file as described. - -### Example - -If a user inputs the directive "Create a default log4j configuration file" and selects the root directory of their Java -project, the system might generate a file named `log4j.properties` with standard logging configurations, placing it in -an appropriate directory within the project. - -### Conclusion - -The `CreateFileAction` class streamlines the process of creating new files within a project, guided by natural language -directives. It simplifies tasks that would otherwise require manual file creation and content generation, thereby -enhancing developer productivity. - -# generic\CodeChatAction.kt - -## CodeChatAction Documentation - -### Overview - -The `CodeChatAction` class is part of a plugin designed to enhance coding productivity by integrating a code chat -feature directly into your development environment. This feature allows developers to engage in discussions about code -snippets, share insights, and collaborate more effectively. - -### Key Features - -- **Code Selection Sharing:** Share selected code snippets or entire files with collaborators in real-time. -- **Language Detection:** Automatically detects the programming language of the shared code for syntax highlighting and - context-aware discussions. -- **Session Management:** Creates unique sessions for each code chat, ensuring discussions are organized and easily - accessible. -- **Browser Integration:** Opens the code chat in the default web browser, providing a seamless transition from code - editor to discussion platform. - -### How It Works - -1. **Initialization:** When the action is triggered, the plugin checks for an active editor and the selected text within - it. If no text is selected, the entire document's text is used. -2. **Session Creation:** A unique session ID is generated for the code chat session. This session is associated with the - selected code snippet or document, the detected programming language, and other relevant metadata. -3. **Code Chat Server:** The plugin interacts with an `AppServer` instance to register the code chat session and - initialize the necessary backend services, including a `ChatServer` for managing chat sessions. -4. **Opening the Chat:** After a brief delay to ensure server readiness, the plugin attempts to open the code chat in - the user's default web browser, directing them to the specific session URL. - -### Requirements - -- **IDE Support:** The plugin is designed to work within an IDE that supports the IntelliJ Platform, such as IntelliJ - IDEA. -- **Desktop Environment:** Requires a desktop environment capable of opening web URLs in a browser. - -### Usage - -To use the `CodeChatAction`, follow these steps: - -1. **Select Code:** In your IDE, select the code snippet you wish to discuss. -2. **Trigger Action:** Trigger the `CodeChatAction` through the designated shortcut or menu option. -3. **Engage in Discussion:** Once the code chat session opens in your browser, you can start discussing the code with - your collaborators. - -### Troubleshooting - -- **Browser Not Opening:** Ensure your default web browser is set correctly and can be launched from your desktop - environment. -- **Session Not Created:** Check your IDE's log for any errors related to the `CodeChatAction` or network issues that - may prevent session creation. - -For further assistance, consult the plugin's support resources or contact the development team. - -# generic\DictationAction.kt - -## DictationAction Plugin Documentation - -### Overview - -The DictationAction plugin is designed to enhance your coding experience by allowing you to dictate code and comments -directly into your IDE. This innovative tool captures your voice, processes the audio, and converts it into text, -inserting the transcribed text at the current cursor position or replacing the selected text in your editor. - -### Features - -- **Voice to Text Conversion**: Transcribe your voice into text directly in the IDE editor. -- **Continuous Dictation**: Dictate for as long as you need; the transcription stops when you close the status dialog. -- **Automatic Insertion**: The transcribed text is automatically inserted at the cursor's position or replaces the - selected text. -- **Background Processing**: Audio recording, processing, and transcription run in separate threads, ensuring the IDE - remains responsive. - -### How to Use - -1. **Start Dictation**: Trigger the DictationAction from the IDE's action menu. A status dialog appears indicating that - dictation is active. -2. **Dictate Your Code or Comments**: Speak clearly into your microphone. Your voice is captured, processed, and - transcribed into text in real-time. -3. **Stop Dictation**: Close the status dialog window to stop the dictation process. The transcription stops, and any - remaining audio is processed and inserted into the editor. - -### Requirements - -- A microphone connected to your computer. -- The DictationAction plugin installed in your IDE. - -### Troubleshooting - -- **Dictation Not Starting**: Ensure your microphone is properly connected and recognized by your system. -- **Poor Transcription Quality**: Speak clearly and at a moderate pace. Background noise can affect transcription - accuracy. -- **IDE Becomes Unresponsive**: Although designed to run in the background, extremely long dictation sessions may impact - IDE performance. Consider dictating in shorter bursts. - -### Support - -For issues, suggestions, or contributions, please visit the DictationAction plugin repository on GitHub. - ---- - -This documentation provides a concise overview of the DictationAction plugin's functionality and usage. For more -detailed information or to contribute to the project, please refer to the project's GitHub page. - -# generic\DiffChatAction.kt - -## DiffChatAction Documentation - -### Overview - -The `DiffChatAction` class is part of a plugin designed to enhance coding productivity by integrating a chat-based -interface for generating and applying code diffs directly within the IDE. This action allows users to select a portion -of code, initiate a chat session, and receive suggestions in the form of diffs. These diffs can then be applied directly -to the code with ease. - -### Features - -- **Code Selection**: Users can select a specific portion of code or use the entire document for the chat session. -- **Chat Session Initiation**: A unique session is created for each chat, allowing for focused and relevant suggestions. -- **Diff Suggestions**: The chat interface provides code modifications in the diff format, making it clear what changes - are suggested. -- **Direct Application of Diffs**: Users can apply suggested diffs directly from the chat interface, streamlining the - code improvement process. -- **Markdown Rendering**: The chat interface renders responses in HTML, providing a rich and user-friendly experience. - -### Usage - -1. **Select Code**: Highlight the code segment you wish to discuss or leave unselected for the entire document. -2. **Activate DiffChatAction**: Trigger the `DiffChatAction` from the IDE's action menu. -3. **Chat Session**: A chat session will open in your default web browser, connected to the selected code segment. -4. **Receive and Apply Diffs**: Engage with the chat to receive diff suggestions. Use provided links to apply diffs - directly to your code. - -### Requirements - -- **IDE Support**: This action is designed for use within an IDE that supports the plugin, such as IntelliJ IDEA. -- **Desktop Environment**: A desktop environment capable of opening web links in a browser. - -### Limitations - -- **Selection Requirement**: For the action to initiate, a text selection or an open document must be present. -- **Browser Dependency**: The action requires a web browser to open the chat interface. - -### Troubleshooting - -- **Browser Not Opening**: Ensure your default web browser is set correctly and is capable of opening new tabs or - windows from external applications. -- **Diff Application Issues**: If diffs are not applying correctly, check for any conflicts or syntax errors in the - suggested changes. - -### Conclusion - -The `DiffChatAction` enhances coding efficiency by integrating a smart, chat-based diff suggestion and application -mechanism directly within the IDE. By streamlining the process of reviewing and applying code changes, it offers a novel -approach to code improvement and collaboration. - -# generic\MultiDiffChatAction.kt - -## MultiDiffChatAction Documentation - -### Overview - -The `MultiDiffChatAction` class is part of a larger system designed to facilitate coding assistance through a chat -interface. This action allows users to interact with an AI model that provides coding help in the form of code diffs. -Users can submit multiple files, and the AI will generate responses that include code modifications, explanations, and -suggestions. - -### Key Features - -- **Multi-File Support**: Users can submit multiple code files in different programming languages. The action processes - these files and prepares them for analysis by the AI model. -- **Dynamic Code Analysis**: The AI model analyzes the submitted code and generates responses that may include code - modifications, suggestions, and explanations. -- **Interactive Chat Interface**: Users interact with the AI through a chat interface, making it easier to ask questions - and receive assistance. -- **Real-Time Code Updates**: The action supports applying suggested code changes directly to the source files, allowing - users to quickly adopt the AI's recommendations. - -### How It Works - -1. **File Submission**: Users submit one or more code files through the interface. The action identifies the programming - language of each file based on its extension and prepares the content for analysis. - -2. **AI Interaction**: The submitted code is sent to an AI model designed to assist with coding tasks. The model - generates responses based on the code analysis, which may include code diffs, explanations, and suggestions. - -3. **Response Rendering**: The AI's responses are rendered in a chat interface. Code diffs are presented in a way that - users can easily understand the suggested changes. The action also supports rendering the responses in Markdown - format for better readability. - -4. **Applying Changes**: Users have the option to apply the suggested code changes directly from the chat interface. The - action updates the source files with the new code, reflecting the AI's recommendations. - -### Usage - -To use the `MultiDiffChatAction`, follow these steps: - -1. **Initiate Action**: Trigger the action from within the supported environment (e.g., an IDE or a web interface). - -2. **Submit Files**: Select and submit the code files you want assistance with. You can submit files in different - programming languages. - -3. **Interact with AI**: Use the chat interface to ask questions or request assistance. The AI will analyze your code - and provide responses. - -4. **Apply Suggestions**: Review the AI's suggestions and apply any desired code changes directly through the interface. - -### Requirements - -- Compatible IDE or web interface for initiating the action. -- Internet connection for interacting with the AI model and applying code changes. - -### Conclusion - -The `MultiDiffChatAction` offers a novel way to receive coding assistance through an interactive chat interface. By -leveraging AI models to analyze code and generate suggestions, users can improve their code quality and efficiency. This -documentation provides a basic understanding of how to use the action and benefit from its features. - -# generic\LineFilterChatAction.kt - -## LineFilterChatAction Documentation - -### Overview - -The `LineFilterChatAction` class is part of a plugin designed to enhance coding productivity by providing an interactive -chat interface. This interface allows users to ask questions and receive assistance with their code directly within -their IDE. The action integrates with a chat model to analyze and respond to queries based on the selected or entire -code in the current editor. - -### Features - -- **Code Contextual Chat**: Engage in a chat session where the AI understands the context of your code, including - language and content. -- **Markdown Support**: Responses from the AI can include markdown formatting for better readability and structure. -- **Line Reference**: The AI can reference specific lines in its responses, making it easier to understand suggestions - or corrections. - -### How It Works - -1. **Activation**: The action is triggered within the IDE. It requires an active editor window with code. -2. **Session Creation**: A unique chat session is created for the interaction. -3. **Code Analysis**: The action extracts the code from the current editor, either the selected text or the entire - document if no text is selected. -4. **Chat Interface**: The user is directed to a web-based chat interface where they can ask questions and receive - responses related to the code. -5. **Interactive Responses**: The AI model provides responses, potentially including markdown and references to specific - lines in the code. - -### Requirements - -- An active editor window in the IDE with the code you want to discuss. -- Desktop environment capable of opening web browsers for the chat interface. - -### Usage - -1. **Select Code** (Optional): Select a specific portion of code in the editor if you want to focus the chat on that - segment. -2. **Trigger Action**: Use the designated shortcut or menu option to activate the `LineFilterChatAction`. -3. **Chat Session**: A browser window/tab will open, directing you to the chat interface. Wait a moment if it doesn't - open immediately. -4. **Ask Questions**: Start asking your questions or discussing your code with the AI in the chat interface. -5. **Review Responses**: The AI's responses may include markdown formatting and line references for clarity. - -### Troubleshooting - -- **Browser Not Opening**: Ensure your desktop environment supports opening web links and that no software is blocking - the action. -- **No Response in Chat**: Verify your internet connection and ensure the server hosting the chat model is operational. - -### Conclusion - -The `LineFilterChatAction` enhances coding efficiency by providing an AI-powered chat interface for real-time code -assistance. It leverages the context of your code, including language and structure, to offer relevant and interactive -support. - -# generic\DocumentationCompilerAction.kt - -## Documentation Compiler Action - -The Documentation Compiler Action is a feature designed for IntelliJ-based IDEs that assists developers in automatically -generating documentation for their projects. This action compiles documentation from selected files within a project, -leveraging natural language processing to enhance the documentation process. - -### Features - -- **Automatic Documentation Generation**: Automatically compiles documentation from selected project files. -- **Customizable Output**: Users can specify the output filename and the transformation message to tailor the - documentation process. -- **File Selection**: Allows users to select specific files for documentation compilation. -- **Concurrency Support**: Utilizes multi-threading to speed up the documentation compilation process. - -### How to Use - -1. **Select Files**: Right-click on a folder or a selection of files in your project that you wish to document. -2. **Configure Settings**: Upon triggering the action, a settings dialog will appear. Here, you can configure: - - **Transformation Message**: A custom message to guide the documentation transformation process. - - **Output Filename**: The name of the file where the compiled documentation will be saved. - - **Files to Process**: Select or deselect files to include in the documentation compilation. -3. **Compile Documentation**: After configuring the settings, proceed to compile the documentation. The action will - process the selected files, applying natural language processing to generate or enhance the documentation content. - -### Implementation Details - -- **File Selection Validation**: The action is only enabled for directories, ensuring that documentation is compiled at - a folder level. -- **Concurrency**: Utilizes a fixed thread pool to process multiple files concurrently, enhancing performance. -- **Dynamic Output File Naming**: If the specified output file already exists, the action automatically generates a new - filename to prevent overwriting. -- **IDE Integration**: Seamlessly integrates with the IDE's file system and editor, automatically opening the generated - documentation upon completion. - -### Requirements - -- IntelliJ-based IDE (e.g., IntelliJ IDEA, PyCharm) -- Java Development Kit (JDK) - -### Installation - -This action is part of a plugin package. To install: - -1. Open your IDE and navigate to the plugin marketplace. -2. Search for the plugin package containing `DocumentationCompilerAction`. -3. Install the plugin and restart your IDE. - -### Conclusion - -The Documentation Compiler Action streamlines the process of generating project documentation, making it easier for -developers to maintain up-to-date documentation for their projects. By automating the documentation process and -integrating directly with the IDE, this action saves time and enhances the quality of project documentation. - -# generic\RedoLast.kt - -## RedoLast Action for IntelliJ - -### Overview - -The RedoLast action is a feature designed for IntelliJ users who are utilizing AI Coder. It enables users to easily redo -the last AI Coder action they executed within the editor. This functionality is particularly useful for quickly -reverting and reapplying changes made by AI Coder, enhancing productivity and workflow efficiency. - -### How to Use - -To utilize the RedoLast action, follow these simple steps: - -1. **Open the Editor**: Ensure you are in the IntelliJ editor where you previously performed an AI Coder action. -2. **Access the Context Menu**: Right-click within the editor to open the context menu. -3. **Select RedoLast**: Look for the RedoLast action in the context menu and select it. - -Upon selection, the RedoLast action will automatically redo the last AI Coder action that was performed in the editor. - -### Availability - -The RedoLast action is available only when there is a previous AI Coder action to redo. If no such action exists, the -RedoLast option will be disabled. - -### Key Features - -- **Ease of Use**: Quickly redo the last AI Coder action with a simple selection from the context menu. -- **Efficiency**: Saves time by allowing users to easily revert and reapply changes. -- **Integration**: Seamlessly works within the IntelliJ environment, enhancing the AI Coder experience. - -### Requirements - -To use the RedoLast action, you must have: - -- IntelliJ IDE installed. -- AI Coder plugin enabled in your IntelliJ environment. - -### Conclusion - -The RedoLast action is a valuable tool for developers using AI Coder in IntelliJ, offering a quick and efficient way to -redo actions. By integrating this feature into your workflow, you can enhance your productivity and streamline your -development process. - -# generic\ReplaceOptionsAction.kt - -## ReplaceOptionsAction Documentation - -### Overview - -`ReplaceOptionsAction` is an IntelliJ IDEA plugin action designed to assist developers by suggesting alternative text -options for a selected piece of code or text within the IDE. This action leverages a virtual API to generate suggestions -based on the context surrounding the selected text, aiming to enhance code quality and developer productivity. - -### Key Features - -- **Context-Aware Suggestions:** Generates text suggestions based on the content before and after the selected text, - ensuring relevance. -- **Customizable Suggestions:** Utilizes a virtual API, allowing for customization of the suggestion engine. -- **User-Friendly Interface:** Offers a simple dialog with radio buttons for users to choose from the generated - suggestions. - -### How It Works - -1. **Selection:** The user selects a piece of text within their code. -2. **Context Analysis:** The plugin calculates an ideal length for context analysis and extracts the text before and - after the selection. -3. **Suggestion Generation:** The virtual API is called with the contextual information to generate a list of - suggestions. -4. **User Selection:** A dialog is presented to the user, allowing them to choose one of the suggested options to - replace the selected text. - -### Components - -#### VirtualAPI Interface - -Defines the contract for the suggestion engine, including the `suggestText` method which takes a template string and a -list of examples to generate suggestions. - -##### Suggestions Class - -A nested class within `VirtualAPI` that holds the generated suggestions. - -#### Proxy - -A property that initializes the virtual API proxy with configuration settings from `AppSettingsState`, such as the model -and temperature for generating suggestions. - -### Usage - -- **Initialization:** The action is initialized within the IntelliJ IDEA environment and listens for user selection. -- **Selection:** The user highlights the text they wish to replace. -- **Execution:** The action is triggered, either via a menu option or a shortcut, initiating the suggestion generation - process. -- **Choice:** The user is presented with a dialog to choose one of the generated suggestions. -- **Replacement:** The selected suggestion replaces the original text. - -### Configuration - -The action utilizes settings from `AppSettingsState` for configuring the virtual API, including: - -- The default chat model. -- The temperature setting for suggestion variability. - -### Extensibility - -Developers can extend `ReplaceOptionsAction` to customize the suggestion process or the user interface for selecting -suggestions. The `choose` method can be overridden to implement different mechanisms for presenting and selecting among -the suggestions. - -### Conclusion - -`ReplaceOptionsAction` is a powerful tool for IntelliJ IDEA users, offering smart, context-aware suggestions to improve -code quality and accelerate development workflows. Through its integration with a virtual API, it provides a flexible -and customizable solution for code enhancement. - -# markdown\MarkdownImplementActionGroup.kt - -## Markdown Implement Action Group Documentation - -The `MarkdownImplementActionGroup` is an extension designed for IntelliJ-based IDEs that enhances your Markdown editing -capabilities by allowing you to automatically generate code snippets in various programming languages directly from your -Markdown files. This feature is particularly useful for developers, technical writers, and educators who frequently -create technical documentation or tutorials. - -### Features - -- **Multi-Language Support**: Supports a wide range of programming languages including SQL, Java, C, C++, Python, Ruby, - and many more, allowing you to generate code snippets in the language of your choice. -- **Automatic Code Generation**: Utilizes a conversion API to transform selected text into code snippets, making it - easier to include code examples in your Markdown files. -- **Easy Integration**: Seamlessly integrates with your development environment, providing a straightforward way to - enhance your Markdown documents without leaving your IDE. - -### How It Works - -1. **Language Detection**: The action group first checks if the current file is a Markdown file and if there is a text - selection within it. -2. **Action Visibility**: If the conditions are met, the action becomes visible and enabled in the IDE's context menu. -3. **Code Generation**: Upon selection of the desired programming language from the context menu, the extension - communicates with a conversion API to generate a code snippet based on the selected text. -4. **Snippet Insertion**: The generated code snippet is then formatted and inserted into the Markdown document, wrapped - in the appropriate code block syntax for the selected language. - -### Usage - -To use the `MarkdownImplementActionGroup`, follow these steps: - -1. Open a Markdown file in your IntelliJ-based IDE. -2. Select the text you wish to convert into a code snippet. -3. Right-click to open the context menu and navigate to the `Markdown Implement Action Group` submenu. -4. Choose the programming language for your code snippet from the list. -5. The extension will automatically generate and insert the code snippet into your document. - -### Requirements - -- IntelliJ-based IDE (e.g., IntelliJ IDEA, PyCharm, WebStorm) -- Java Development Kit (JDK) - -### Installation - -This extension can be installed from the JetBrains Marketplace or by downloading the plugin JAR file and installing it -manually through your IDE's plugin settings. - -### Conclusion - -The `MarkdownImplementActionGroup` is a powerful tool for anyone involved in creating or editing Markdown documents that -include code snippets. By automating the code generation process, it not only saves time but also ensures consistency -and accuracy in your documentation. - -# generic\WebDevAction.kt - -## Web Development Assistant Plugin Documentation - -### Overview - -The Web Development Assistant is an IntelliJ IDEA plugin designed to streamline the process of developing web -applications. It leverages AI to assist in generating code, reviewing code, and suggesting architectural designs for web -projects directly within the IDE environment. - -### Features - -- **Code Generation**: Automatically generates HTML, CSS, and JavaScript code based on user input. -- **Code Review**: Analyzes code for potential issues and suggests improvements or fixes. -- **Architecture Suggestion**: Provides detailed architecture suggestions for web applications, including - framework/library recommendations and CDN links. -- **Session Management**: Supports multiple development sessions with unique settings and resources. -- **Interactive Feedback**: Allows users to provide feedback on generated code and suggestions, facilitating iterative - improvement. - -### Getting Started - -1. **Installation**: Ensure the plugin is installed in your IntelliJ IDEA environment. -2. **Accessing the Plugin**: Navigate to the plugin through IntelliJ IDEA's action or menu system. -3. **Starting a Session**: Initiate a new web development session by selecting a target folder for your project. -4. **Interacting with the Assistant**: Provide your requirements or queries to the assistant through the provided UI. - The assistant will generate code, review existing code, or suggest architectural designs based on your input. -5. **Reviewing Suggestions**: Examine the assistant's output, which may include code snippets, architectural designs, or - code review comments. -6. **Providing Feedback**: Use the interactive feedback system to refine the suggestions, asking for revisions or - clarifications as needed. - -### Key Components - -- **WebDevAction**: The main class that handles user actions, initiating sessions, and opening the browser interface for - interaction. -- **WebDevApp**: Represents a web development session, managing settings, user messages, and interactions with the AI. -- **WebDevAgent**: Acts as the intermediary between the user and the AI, handling specific tasks like code generation, - code review, and architecture suggestion. -- **Session Management**: Sessions are uniquely identified and managed, allowing for persistent settings and - interactions within a project. - -### Usage Tips - -- **Clear Requirements**: Provide clear and concise requirements to the assistant for more accurate suggestions. -- **Iterative Feedback**: Use the feedback loop effectively by reviewing suggestions and providing specific feedback for - improvements. -- **Explore Architectural Suggestions**: Take advantage of the architectural suggestions for insights on structuring - your web application and selecting appropriate technologies. - -### Troubleshooting - -- **Browser Issues**: If the browser does not open automatically, manually navigate to the provided URL. -- **Session Persistence**: Ensure your project folder is correctly selected to maintain session continuity. -- **Feedback Loop**: If feedback is not being correctly processed, ensure you are providing it in the expected format - and context. - -### Conclusion - -The Web Development Assistant plugin offers a powerful toolset for accelerating web development projects by integrating -AI-driven code generation, review, and architectural suggestions directly into the IntelliJ IDEA environment. By -following the guidelines and making effective use of the features, developers can enhance their productivity and focus -on creative aspects of web development. - -# markdown\MarkdownListAction.kt - -## Markdown List Action Documentation - -### Overview - -The `MarkdownListAction` class is designed to enhance your Markdown editing experience in IntelliJ-based IDEs by -automatically generating and inserting list items into your Markdown files. This action is particularly useful when -you're looking to quickly expand lists with new, contextually relevant items without manually brainstorming and typing -each one. - -### Features - -- **Automatic List Item Generation:** Leverages AI to generate new list items based on the existing ones in your - Markdown document. -- **Context-Aware:** Understands the context of your list to provide relevant suggestions. -- **Customizable Item Count:** Allows specifying the number of new items to generate. -- **Support for Different Bullet Types:** Works with various bullet types including `- [ ]` (task list), `-`, and `*`. - -### How It Works - -1. **Selection Identification:** The action identifies the list you're working on based on your text selection in a - Markdown file. -2. **Item Extraction:** It extracts existing list items and sends them to an AI service, which then generates additional - items based on the context. -3. **List Expansion:** The new items are inserted into your document, directly after the selected list, maintaining the - original list's formatting and bullet type. - -### Usage - -To use the `MarkdownListAction`, follow these steps: - -1. **Open a Markdown File:** Ensure you're working in a file recognized as Markdown by your IDE. -2. **Select a List:** Highlight a portion of the list you wish to expand. It's important that the selection includes - part of the list recognized by the IDE as `MarkdownListImpl`. -3. **Activate the Action:** Trigger the `MarkdownListAction`. This can be done through a menu option or a keyboard - shortcut, depending on how it's configured in your IDE. -4. **Wait for Generation:** The action communicates with an AI service to generate new items. Once the process is - complete, the new items are automatically inserted into your document. - -### Requirements - -- IntelliJ-based IDE (e.g., IntelliJ IDEA, PyCharm, WebStorm) -- Active internet connection for AI service communication -- Plugin or configuration that recognizes `MarkdownListAction` - -### Limitations - -- The quality and relevance of the generated list items depend on the AI model's understanding of the context. -- Requires the document to be properly formatted as Markdown for accurate context recognition and bullet type matching. - -### Conclusion - -The `MarkdownListAction` is a powerful tool for enhancing productivity and creativity when working with Markdown lists -in IntelliJ-based IDEs. By automating the generation and insertion of list items, it allows users to focus more on -content creation and less on manual list management. - diff --git a/build.gradle.kts b/build.gradle.kts index ac0518d8..b9618a87 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -26,7 +26,7 @@ repositories { val kotlin_version = "2.0.0-Beta5" val jetty_version = "11.0.18" val slf4j_version = "2.0.9" -val skyenet_version = "1.0.62" +val skyenet_version = "1.0.63" val remoterobot_version = "0.11.21" dependencies { @@ -39,7 +39,7 @@ dependencies { exclude(group = "org.jetbrains.kotlin", module = "") } - implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.0.51") + implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.0.52") { exclude(group = "org.jetbrains.kotlin", module = "") } diff --git a/counters.json b/counters.json deleted file mode 100644 index 70e879c4..00000000 --- a/counters.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "20231113-5ea3aa8c" : { - "tokensPerModel" : { - "GPT35Turbo" : 452 - } - }, - "20231113-83f5627c" : { - "tokensPerModel" : { - "GPT35Turbo" : 454 - } - } -} \ No newline at end of file diff --git a/docs/action_documentation.md b/docs/action_documentation.md index b148c503..2e4be416 100644 --- a/docs/action_documentation.md +++ b/docs/action_documentation.md @@ -1,2124 +1,1730 @@ -# code\DocAction.kt +# Project User Documentation + +Welcome to the user documentation for our IntelliJ IDEA plugin suite, designed to enhance your development experience +with a variety of actions. This document provides an overview of the available actions, categorized for easy reference, +and instructions on how to use them to improve your coding efficiency. + +## Table of Categorized Actions + +- `DiffChatAction`: Engages in a chat session to generate and apply code diffs directly within the IDE. +- **Collaboration and Review** + - `DiffChatAction`: Initiates a chat session for collaborative code review and diff generation. + - `MultiDiffChatAction`: Allows for collaborative code review and diff generation across multiple files. + - `LineFilterChatAction`: Provides an interactive chat interface for discussing specific lines of code. + - `CodeChatAction`: Offers a real-time chat interface for discussing code snippets and receiving AI-powered coding assistance. + +## How to Use Actions + +- **Code Editing Actions** + - `CustomEditAction`: Trigger this action to open a dialog where you can input a natural language instruction for + editing your selected code. + - `ImplementStubAction`: Automatically selects code elements that match stub patterns and implements them based on + AI suggestions. + - `PasteAction`: Simply copy text to your clipboard and use this action to paste it as converted code in your + editor. + - `RenameVariablesAction`: Select a block of code and trigger this action to receive suggestions for renaming + variables. +- **Documentation Actions** + - `DocAction`: Select a code block and activate this action to generate and insert documentation above the selected + block. + - `GenerateDocumentationAction`: Select files or folders in your project, trigger this action, and specify output + settings to compile documentation. +- **Code Comments Actions** + - `CommentsAction`: Highlight a code block and activate this action to automatically add comments explaining the + code. + - `DescribeAction`: Use this action to generate a detailed description of the selected code, enhancing its + documentation. +- **Code Generation Actions** + - `InternalCoderAction`: Start a coding session with this action to receive coding assistance directly in the IDE. + - `WebDevelopmentAssistantAction`: Trigger this action for AI-powered assistance with web development tasks, including code + generation and architecture suggestions. + - `MultiStepPatchAction`: Automates development tasks by translating user directives into actionable development tasks and code modifications. +- **Markdown Enhancement Actions** + - `MarkdownImplementActionGroup`: In a Markdown file, select text and use this action to generate code snippets in + various languages. + - `MarkdownListAction`: Highlight a list in your Markdown file and activate this action to automatically generate + and insert new list items. +- **Development Workflow Actions** + - `RecentCodeEditsAction`: Access this action to see a list of your most recent code edits and quickly reapply any + of them. + - `RedoLast`: Use this action to redo the last AI Coder action you executed, enhancing your workflow efficiency. +- **Text Transformation Actions** + - `AppendTextWithChatAction`: Select text and trigger this action to append AI-generated text, expanding on your initial + selection. + - `ReplaceWithSuggestionsAction`: Highlight text and activate this action to receive and choose from AI-generated text + options for replacement. + +Each action is designed to seamlessly integrate into your development workflow, offering a range of enhancements from +code editing to documentation and AI integration. Explore these actions to discover how they can improve your +productivity and coding experience in IntelliJ IDEA. -Sure, here's the documentation for the `DocAction` class: +# code\CustomEditAction.kt -```kotlin -/** - * The `DocAction` class is an implementation of the `SelectionAction` interface that generates - * documentation for a selected code block using OpenAI's language model. - * - * The class defines a virtual API interface `DocAction_VirtualAPI` that provides a single method - * `processCode` to generate the documentation text. The `ChatProxy` class is used to create an - * instance of this virtual API, which is initialized with an example input-output pair. - * - * The `processSelection` method is the main entry point for the action. It takes the selected text - * from the editor, formats it as an `IndentedText` object, and passes it to the `processCode` method - * of the virtual API along with the language and documentation style. The generated documentation - * text is then prepended to the original code and returned. - * - * The `isLanguageSupported` method checks if the given `ComputerLanguage` is supported for - * documentation generation by verifying that it is not plain text and has a non-empty documentation - * style defined. - * - * The `editSelection` method is overridden to handle cases where the selected text is not the entire - * code block. It uses the `PsiUtil` class to find the enclosing code element and adjusts the selection - * range accordingly. - * - * @param project The current project instance (not used in this implementation). - * @param state The `SelectionState` object containing the selected text and language information. - * @param config An optional configuration string (not used in this implementation). - * @return The generated documentation text prepended to the original code. - */ -class DocAction : SelectionAction() { ... } -``` +## CustomEditAction Documentation -This documentation explains the purpose of the `DocAction` class, its main methods and their responsibilities, and the parameters and return values of the `processSelection` method. It also mentions the use of the `ChatProxy` class and the `PsiUtil` utility class. +### Overview -# code\DescribeAction.kt +The `CustomEditAction` class extends the functionality of `SelectionAction` to provide a mechanism for editing code +based on user instructions. It leverages a virtual API to process the code modifications, which can include operations +like adding comments, refactoring, or any other code transformation specified by the user. This action is designed to +integrate with an IDE environment, allowing users to easily modify their code using natural language instructions. -Sure, here's the documentation for the `DescribeAction` class: +### Key Components -```kotlin -/** - * The DescribeAction class is an implementation of the SelectionAction interface. - * It is responsible for generating a description of the selected code using OpenAI's language model. - * - * The class defines a virtual API interface called DescribeAction_VirtualAPI, which contains a single method: - * - describeCode(code: String, computerLanguage: String, humanLanguage: String): DescribeAction_ConvertedText - * This method takes the selected code, the programming language of the code, and the human language for the description. - * It returns an instance of DescribeAction_ConvertedText, which contains the generated description and its language. - * - * The DescribeAction class uses the ChatProxy class to create an instance of the DescribeAction_VirtualAPI interface. - * The ChatProxy is configured with the appropriate API key, temperature, and language model settings from the AppSettingsState. - * - * The processSelection method is the main entry point for the action. It takes a SelectionState object, which contains - * the selected text, the programming language, and other context information. It then calls the describeCode method - * of the DescribeAction_VirtualAPI instance to generate the description. - * - * The generated description is then wrapped to a maximum line length of 120 characters using the StringUtil.lineWrapping - * method. Based on the number of lines in the wrapped description, the method determines whether to use a line comment - * or a block comment style for the programming language. - * - * Finally, the method returns a string that combines the comment style with the original selected text, indented - * appropriately. - */ -``` +#### VirtualAPI Interface + +- **Purpose**: Defines the contract for the code editing service. +- **Methods**: + - `editCode(code: String, operation: String, computerLanguage: String, humanLanguage: String)`: Takes the original + code, an operation in natural language, the programming language of the code, and the human language of the + operation. Returns an `EditedText` object containing the modified code. + +- **EditedText Data Class**: + - Holds the result of the code editing operation, including the modified code and its language. + +#### CustomEditAction Class + +- **Functionality**: Allows users to input natural language instructions to edit selected code within an IDE. +- **Key Methods**: + - `getConfig(project: Project?)`: Displays a dialog to the user to input the editing instruction. + - `processSelection(state: SelectionState, instruction: String?)`: Processes the user's instruction on the selected + code and returns the edited code. + +#### Proxy Property + +- **Purpose**: Creates an instance of the `VirtualAPI` using a `ChatProxy`, pre-configured with examples and settings + from `AppSettingsState`. +- **Functionality**: It demonstrates how to use the virtual API by adding an example of code editing and then creates + the proxy instance that will be used for actual code editing operations. -This class is part of the `com.github.simiacryptus.aicoder.actions.code` package and is used in the context of an IntelliJ IDEA plugin for generating code descriptions using OpenAI's language model. It leverages the `SelectionAction` interface and other utility classes from the project to interact with the user's code selection and generate a descriptive comment. +### Usage + +1. **Invoke CustomEditAction**: This action can be triggered within an IDE environment where it is integrated. +2. **Input Instruction**: When prompted, the user inputs a natural language instruction detailing how the selected code + should be edited. +3. **Code Transformation**: The action processes the instruction and applies the specified edits to the selected code. + +### Integration Points + +- **AppSettingsState**: Utilizes application settings for configuring the chat proxy, including the model to use and the + temperature setting for the AI's responses. +- **UITools**: Used for displaying the input dialog to the user. + +### Example + +If a user selects a piece of code and inputs the instruction "Add code comments explaining the +function", `CustomEditAction` will process this instruction, potentially resulting in the selected code being annotated +with comments that explain its functionality, based on the capabilities of the underlying virtual API. + +### Conclusion + +`CustomEditAction` provides a powerful and intuitive way for developers to edit and refactor their code using natural +language instructions, seamlessly integrating AI-powered code transformation into their development workflow. # code\CommentsAction.kt -Sure, here's the documentation for the `CommentsAction` class: +#### CommentsAction Class Documentation -```kotlin -/** - * The CommentsAction class is an implementation of the SelectionAction interface. - * It is responsible for adding comments to the selected code in the IDE. - * - * The action uses the OpenAI API to generate comments for the selected code. - * It sends the selected code, the desired operation (adding comments), the computer language, - * and the human language to the OpenAI API, which generates the commented code. - * - * The action supports all computer languages except for plain text. - */ -class CommentsAction : SelectionAction() { - - /** - * Returns an empty string as the configuration for this action. - * - * @param project The current project. - * @return An empty string. - */ - override fun getConfig(project: Project?): String { - return "" - } - - /** - * Checks if the given computer language is supported by this action. - * - * @param computerLanguage The computer language to check. - * @return True if the language is not null and not plain text, false otherwise. - */ - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - return computerLanguage != null && computerLanguage != ComputerLanguage.Text - } - - /** - * Processes the selected text by adding comments to each line of code. - * - * @param state The selection state containing the selected text and language. - * @param config The configuration for this action (not used). - * @return The commented code. - */ - override fun processSelection(state: SelectionState, config: String?): String { - return ChatProxy( - clazz = CommentsAction_VirtualAPI::class.java, - api = api, - temperature = AppSettingsState.instance.temperature, - model = AppSettingsState.instance.defaultChatModel(), - deserializerRetries = 5 - ).create().editCode( - state.selectedText ?: "", - "Add comments to each line explaining the code", - state.language.toString(), - AppSettingsState.instance.humanLanguage - ).code ?: "" - } - - /** - * The CommentsAction_VirtualAPI interface defines the contract for the OpenAI API call. - */ - interface CommentsAction_VirtualAPI { - /** - * Edits the given code by performing the specified operations. - * - * @param code The code to edit. - * @param operations The operations to perform on the code. - * @param computerLanguage The computer language of the code. - * @param humanLanguage The human language for the comments. - * @return The edited code with comments. - */ - fun editCode( - code: String, - operations: String, - computerLanguage: String, - humanLanguage: String - ): CommentsAction_ConvertedText - - /** - * The CommentsAction_ConvertedText class represents the result of the editCode operation. - */ - class CommentsAction_ConvertedText { - var code: String? = null - var language: String? = null - } - } -} -``` +The `CommentsAction` class is part of the AI Coder extension, designed to enhance code readability by automatically +adding comments to the selected code block within your IDE. This class extends the functionality +of `SelectionAction`, allowing it to process selected text and utilize AI services to generate insightful +comments. -This documentation explains the purpose of the `CommentsAction` class, the responsibilities of each method, and the interfaces it uses. It also provides information about the parameters and return values of each method. +##### Features -# code\CustomEditAction.kt +- **Language Support**: The action is designed to work with a variety of programming languages, excluding plain text. It + ensures that the feature is only applied to code, where commenting is beneficial. +- **AI-Powered**: Utilizes the `ChatProxy` class to communicate with an AI model, specifically tailored to generate + comments for code. This integration allows for context-aware, meaningful comments that improve code understanding. +- **Customizable**: Leverages settings from `AppSettingsState` to allow customization of the AI's behavior, including + the model's temperature and the choice of language model, adapting the comments to the user's preferences. -Sure, here's the documentation for the `CustomEditAction` class: +##### Key Methods -```kotlin -/** - * An action that allows the user to edit code using natural language instructions. - * The action prompts the user for an instruction, and then uses the OpenAI API to generate - * the edited code based on the user's selection and instruction. - */ -open class CustomEditAction : SelectionAction() { - - /** - * A virtual API interface that defines the `editCode` function. - * This function takes the code, operation, computer language, and human language as input, - * and returns an `EditedText` object containing the edited code and language. - */ - interface VirtualAPI { - fun editCode( - code: String, - operation: String, - computerLanguage: String, - humanLanguage: String - ): EditedText - - data class EditedText( - var code: String? = null, - var language: String? = null - ) - } - - /** - * Returns a proxy instance of the `VirtualAPI` interface. - * The proxy is configured with the OpenAI API, temperature, and model settings from the app settings. - * It also includes an example of how to use the `editCode` function. - */ - val proxy: VirtualAPI - get() { - // Implementation details omitted for brevity - } - - /** - * Prompts the user for an instruction using an input dialog. - * @param project The current project. - * @return The user's instruction, or an empty string if the user cancels the dialog. - */ - override fun getConfig(project: Project?): String { - // Implementation details omitted for brevity - } - - /** - * Processes the user's selection and instruction to generate the edited code. - * @param state The selection state containing the selected text and language. - * @param instruction The user's instruction for editing the code. - * @return The edited code, or the original selected text if no instruction is provided. - */ - override fun processSelection(state: SelectionState, instruction: String?): String { - // Implementation details omitted for brevity - } -} -``` +- **getConfig(Project?): String**: Returns a configuration string for the action. Currently, this method returns an + empty string, serving as a placeholder for future configurations. + +- **isLanguageSupported(ComputerLanguage?): Boolean**: Checks if the given programming language is supported by the + action. It returns `true` for all programming languages except for plain text, ensuring the action is applied to + actual code. + +- **processSelection(SelectionState, String?): String**: The core method of the class, it takes the selected code block + and processes it through the AI model to generate and insert comments. It utilizes the `ChatProxy` class to + communicate with the AI, passing parameters such as the selected text, desired operations, and language settings. + +##### CommentsAction_VirtualAPI Interface + +An interface defining the `editCode` method, which is essential for the interaction with the AI model to edit and +comment on the code. It specifies the parameters required for the operation, including the code block, operation +description, computer language, and human language. + +##### CommentsAction_ConvertedText Class + +A nested class within the `CommentsAction_VirtualAPI` interface, designed to encapsulate the result of the AI's code +commenting process. It contains fields for the commented code (`code`) and the language of the code (`language`), +facilitating easy integration and use of the AI-generated comments within the IDE. + +#### Usage + +To use the `CommentsAction` feature, ensure your IDE project is set up with the AI Coder extension and configured +according to your preferences in `AppSettingsState`. Select a block of code in a supported language, and trigger +the `CommentsAction`. The AI will analyze the selected code and insert comments, enhancing the code's readability and +maintainability. + +This documentation provides a concise overview of the `CommentsAction` class and its functionalities. For further +details or customization options, refer to the source code or extension documentation. + +# code\DocAction.kt + +## DocAction Documentation + +### Overview + +`DocAction` is a specialized action within the AI Coder plugin designed to automatically generate documentation for +selected code blocks within your project. It leverages a virtual API and a chat model to process and convert code into +well-documented text, enhancing readability and maintainability. + +### Key Components + +#### DocAction_VirtualAPI + +An interface that defines the method `processCode`, which takes a code snippet and other parameters to return +a `DocAction_ConvertedText` object containing the generated documentation text and its language. + +##### DocAction_ConvertedText + +A class that holds the resulting documentation text (`text`) and the language of the documentation (`language`). + +#### Proxy Initialization + +Upon instantiation, `DocAction` initializes a `ChatProxy` with a predefined example to guide the documentation +generation process. This setup involves specifying the operation (e.g., "Write detailed KDoc prefix for code block"), +the code language, and the target human language. + +### Functionality + +#### processSelection + +When a code selection is made, `processSelection` is invoked to generate documentation for the selected code block. It +formats the selected text, calls the `processCode` method through the proxy, and prepends the generated documentation to +the original code. -This class extends the `SelectionAction` class and overrides the `getConfig` and `processSelection` methods. The `getConfig` method prompts the user for an instruction using an input dialog, while the `processSelection` method uses the OpenAI API to generate the edited code based on the user's selection and instruction. +#### isLanguageSupported -The `VirtualAPI` interface defines the `editCode` function, which takes the code, operation, computer language, and human language as input, and returns an `EditedText` object containing the edited code and language. The `proxy` property returns an instance of this interface, configured with the OpenAI API settings and an example of how to use the `editCode` function. +Determines if the selected code's language is supported for documentation generation, based on the presence and +non-emptiness of the `docStyle` attribute in the `ComputerLanguage` object. -Overall, this class provides a convenient way for users to edit code using natural language instructions, leveraging the power of the OpenAI API. +#### editSelection + +Adjusts the selection range to encompass the entire code block identified by the PSI (Program Structure Interface) tree, +ensuring that the documentation is generated for the complete logical code block. + +### Usage + +To use `DocAction`, simply select a code block within your project and activate the action. The plugin will +automatically generate and insert the appropriate documentation based on the code's context, language, and specified +documentation style. + +### Configuration + +`DocAction` relies on the `AppSettingsState` for configuration, including the default chat model, temperature for the +chat model's responses, and the target human language for the documentation. + +### Limitations + +- The action does not support plain text (`ComputerLanguage.Text`) or languages without a defined documentation + style (`docStyle`). +- The quality and accuracy of the generated documentation may vary based on the complexity of the code and the + effectiveness of the provided examples to the chat model. + +### Conclusion + +`DocAction` enhances the development experience by automating the documentation process, making code easier to +understand and maintain. By integrating advanced AI models, it offers a sophisticated approach to code documentation, +tailored to the developers' needs. # code\ImplementStubAction.kt -Sure, here's the documentation for the `ImplementStubAction` class: +## ImplementStubAction Documentation -```kotlin -/** - * An action that implements a code stub or declaration based on the selected code and context. - * - * This action is designed to work with code editors and uses the OpenAI API to generate the implementation - * for a given code stub or declaration. It supports various programming languages, excluding plain text. - * - * The action works by extracting the selected code and the smallest intersecting method or function from - * the context. It then sends this information, along with the programming language and the desired output - * language, to the OpenAI API using the `VirtualAPI` interface. - * - * The `VirtualAPI` interface defines a single method `editCode` that takes the code, operation, computer - * language, and human language as input, and returns a `ConvertedText` object containing the generated - * code and the language it's written in. - * - * The `ImplementStubAction` class extends `SelectionAction` and overrides the following methods: - * - * - `isLanguageSupported`: Checks if the given computer language is supported (excludes plain text). - * - `defaultSelection`: Determines the default selection range based on the editor state and offset. - * - `getConfig`: Returns an empty string as no additional configuration is required. - * - `processSelection`: Processes the selected code, extracts the necessary context, and calls the - * `editCode` method of the `VirtualAPI` to generate the implementation. - * - * The action uses the `ChatProxy` class from the `com.simiacryptus.jopenai.proxy` package to create an - * instance of the `VirtualAPI` interface. The `ChatProxy` is configured with the OpenAI API key, the - * desired model, temperature, and other settings from the `AppSettingsState` class. - * - * @see SelectionAction - * @see VirtualAPI - * @see ChatProxy - * @see AppSettingsState - */ -class ImplementStubAction : SelectionAction() { ... } -``` +### Overview -This documentation explains the purpose of the `ImplementStubAction` class, its dependencies, and the responsibilities of each overridden method. It also provides information about the `VirtualAPI` interface and how the `ChatProxy` is used to interact with the OpenAI API. +The `ImplementStubAction` class is part of a larger framework designed to enhance coding efficiency by automating +certain tasks. This specific action focuses on assisting developers in implementing stubs—placeholders for +functionalities yet to be developed—by leveraging AI-powered code editing capabilities. -# code\RecentCodeEditsAction.kt +### Key Features -Sure, here's the documentation for the `RecentCodeEditsAction` class: +- **Language Support**: Not all programming languages are supported. The action excludes plain + text (`ComputerLanguage.Text`) but supports a variety of other programming languages. +- **Automatic Selection**: It automatically selects the smallest code range that matches a code element within the + editor's current state, providing a default selection for operation. +- **AI-Powered Code Editing**: Utilizes a virtual API to communicate with an AI model, editing code based on the + operation "Implement Stub". This process considers both the computer and human languages set in the application + settings. -```kotlin -/** - * An ActionGroup that displays a list of recent code edits as child actions. - * The child actions are dynamically generated based on the user's recent command history. - * When a child action is selected, it applies the corresponding code edit to the current selection. - */ -class RecentCodeEditsAction : ActionGroup() { - - /** - * Updates the visibility and enabled state of the action based on whether a valid code selection exists. - */ - override fun update(e: AnActionEvent) { - e.presentation.isEnabledAndVisible = isEnabled(e) - super.update(e) - } - - /** - * Generates and returns an array of child actions representing recent code edits. - * Each child action is an instance of CustomEditAction with a specific code edit instruction. - */ - override fun getChildren(e: AnActionEvent?): Array { - if (e == null) return emptyArray() - val children = mutableListOf() - for ((instruction, _) in AppSettingsState.instance.getRecentCommands("customEdits").mostUsedHistory) { - val id = children.size + 1 - val text = if (id < 10) "_$id: $instruction" else "$id: $instruction" - val element = object : CustomEditAction() { - override fun getConfig(project: Project?): String { - return instruction - } - } - element.templatePresentation.text = text - element.templatePresentation.description = instruction - element.templatePresentation.icon = null - children.add(element) - } - return children.toTypedArray() - } - - companion object { - /** - * Checks if the action should be enabled based on the current selection and language. - * The action is enabled if a valid code selection exists (not plain text). - */ - fun isEnabled(e: AnActionEvent): Boolean { - if (!UITools.hasSelection(e)) return false - val computerLanguage = ComputerLanguage.getComputerLanguage(e) - return computerLanguage != ComputerLanguage.Text - } - } -} -``` +### How It Works + +1. **Language Check**: Initially, it checks if the programming language of the code is supported, excluding plain text. +2. **Selection Identification**: It identifies the optimal code selection for the operation by finding the smallest code + range that matches a code element. +3. **Code Processing**: The selected code is processed to remove any suffixes and trimmed. This processed code is then + sent to the AI-powered virtual API. +4. **AI Interaction**: Through the `VirtualAPI`, the action sends the code, operation type ("Implement Stub"), computer + language, and human language to an AI model for processing. +5. **Result**: The AI model returns the edited code, which is then provided as the action's output. + +### VirtualAPI + +An interface within the `ImplementStubAction` class, `VirtualAPI` is crucial for the AI interaction. It defines the +method `editCode` for sending code to the AI model and receiving the edited code. The `ConvertedText` inner class is +used to encapsulate the result, containing the edited code and its language. + +### Usage + +This action is designed to be integrated into a larger system, likely an IDE plugin, where it can be triggered in the +context of editing code. Users do not interact with this action directly but benefit from its functionality during their +development workflow, particularly when implementing stubs or placeholders in their codebase. -This class represents an action group that displays a list of recent code edits as child actions. The child actions are dynamically generated based on the user's recent command history stored in the `AppSettingsState`. +### Configuration -The `update` function updates the visibility and enabled state of the action based on whether a valid code selection exists. The `isEnabled` function checks if the current selection is not plain text, ensuring that the action is only enabled for code selections. +The action requires minimal configuration, primarily relying on the application's settings for determining the human and +computer languages. The `AppSettingsState` singleton is used to fetch these settings, including the AI model's +temperature setting for processing. -The `getChildren` function generates and returns an array of child actions representing recent code edits. Each child action is an instance of `CustomEditAction` with a specific code edit instruction. The text and description of each child action are set based on the instruction and an index number. +### Conclusion -When a child action is selected, it applies the corresponding code edit instruction to the current selection by overriding the `getConfig` function of the `CustomEditAction` class. +The `ImplementStubAction` enhances coding efficiency by automating the implementation of stubs through AI-powered code +editing. It supports various programming languages, automatically identifies the optimal code selection, and leverages a +virtual API for AI interaction, streamlining the development process. # code\PasteAction.kt -Sure, here's the documentation for the `PasteAction` class: +## PasteAction Documentation -```kotlin -/** - * An action that converts the text from the system clipboard into code in the specified language. - * - * This action uses the OpenAI API to convert the clipboard text into code. It supports converting - * text from any language into code in a supported programming language. - * - * The action is enabled only if the system clipboard contains text data. - * - * @see SelectionAction - * @see VirtualAPI - */ -open class PasteAction : SelectionAction(false) { - - /** - * A virtual API interface used to define the contract for the OpenAI API call. - */ - interface VirtualAPI { - /** - * Converts the given text from one language to another. - * - * @param text The text to be converted. - * @param from_language The source language of the text. Use "autodetect" to automatically detect the language. - * @param to_language The target language for the converted text. - * @return The converted text and its language. - */ - fun convert(text: String, from_language: String, to_language: String): ConvertedText - - /** - * A data class representing the converted text and its language. - */ - class ConvertedText { - var code: String? = null - var language: String? = null - } - } - - /** - * Returns an empty string as the configuration for this action. - */ - override fun getConfig(project: Project?): String = "" - - /** - * Processes the selected text by converting it to code using the OpenAI API. - * - * @param state The selection state containing the selected text and language. - * @param config The configuration for the action (not used in this implementation). - * @return The converted code. - */ - override fun processSelection(state: SelectionState, config: String?): String { - return ChatProxy( - VirtualAPI::class.java, - api, - AppSettingsState.instance.defaultChatModel(), - AppSettingsState.instance.temperature, - ).create().convert( - getClipboard().toString().trim(), - "autodetect", - state.language?.name ?: "" - ).code ?: "" - } - - /** - * Checks if the given language is supported by this action. - * - * @param computerLanguage The language to check. - * @return `true` if the language is supported (not plain text), `false` otherwise. - */ - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean = - computerLanguage != null && computerLanguage != ComputerLanguage.Text - - /** - * Checks if the action should be enabled based on the current event. - * - * @param event The action event. - * @return `true` if the system clipboard contains text data, `false` otherwise. - */ - override fun isEnabled(event: AnActionEvent): Boolean = - hasClipboard() && super.isEnabled(event) - - /** - * Checks if the system clipboard contains text data. - * - * @return `true` if the clipboard contains text data, `false` otherwise. - */ - private fun hasClipboard() = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)?.let { contents -> - return@let when { - contents.isDataFlavorSupported(DataFlavor.stringFlavor) -> true - contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()) -> true - else -> false - } - } ?: false - - /** - * Retrieves the text data from the system clipboard. - * - * @return The text data from the clipboard, or `null` if no text data is available. - */ - private fun getClipboard(): Any? = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)?.let { contents -> - return@let when { - contents.isDataFlavorSupported(DataFlavor.stringFlavor) -> contents.getTransferData(DataFlavor.stringFlavor) - contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()) -> contents.getTransferData(DataFlavor.getTextPlainUnicodeFlavor()) - else -> null - } - } -} -``` +### Overview + +The `PasteAction` class is designed to enhance the functionality of pasting text within the IDE. It automatically +converts the text from the clipboard into a specified programming language, leveraging a virtual API for the conversion +process. This feature is particularly useful for developers working with multiple programming languages or needing to +integrate code snippets from various sources seamlessly. + +### Features + +- **Automatic Language Detection:** The action can automatically detect the source language of the text in the + clipboard. +- **Language Conversion:** Converts the clipboard text to the target programming language as specified by the user's + current context or selection. +- **Clipboard Support:** Efficiently handles text from the clipboard, supporting both plain text and Unicode text + flavors. +- **Language Support Check:** Ensures that the action is only available for supported programming languages, excluding + plain text. + +### Usage + +1. **Clipboard Preparation:** Ensure that the text you wish to convert is copied to your system's clipboard. +2. **Triggering PasteAction:** Use the designated shortcut or menu option to trigger the `PasteAction` within your IDE. +3. **Automatic Conversion:** The action automatically detects the language of the text in the clipboard, converts it to + the target language, and pastes it into your current editor window. + +### Requirements + +- The action requires access to a virtual API (`VirtualAPI`) for converting the text between languages. +- The IDE should have access to the `AppSettingsState` configuration for default model and temperature settings used + during conversion. + +### Limitations + +- The action does not support plain text (`ComputerLanguage.Text`) as a target language for conversion. +- The functionality is dependent on the availability and response of the `VirtualAPI`. + +### API Reference + +#### VirtualAPI + +An interface used for converting text between different programming languages. + +##### Methods + +- `convert(text: String, from_language: String, to_language: String): ConvertedText` - Converts the given text from one + language to another. + +##### Inner Class + +- `ConvertedText` - Holds the result of a conversion, including the converted code and its language. + +### Troubleshooting + +- **Conversion Not Triggering:** Ensure that the clipboard contains text and that the text is in a supported format ( + plain text or Unicode text). +- **Unsupported Language Error:** Check if the target language is supported and not marked as plain text. + +For further assistance, refer to the developer documentation or contact support. + +# code\DescribeAction.kt + +## DescribeAction Documentation + +### Overview + +The `DescribeAction` class is part of a larger system designed to enhance coding efficiency by automatically generating +descriptions for code snippets. This functionality is particularly useful within the context of an IDE (Integrated +Development Environment), where understanding and documenting code can significantly improve readability and +maintainability. + +### Key Components + +#### DescribeAction_VirtualAPI + +This interface defines the core functionality for describing code. It includes a single method, `describeCode`, which +takes a code snippet, the programming language of the code, and the desired language for the description. It returns an +instance of `DescribeAction_ConvertedText`, which contains the generated description. + +##### DescribeAction_ConvertedText -This class extends the `SelectionAction` class and provides an action that converts the text from the system clipboard into code in the specified language. The conversion is performed using the OpenAI API, and the action supports converting text from any language into code in a supported programming language. +A simple data class that holds the result of the code description process. It has two properties: `text`, which is the +generated description of the code, and `language`, indicating the language used for the description. -The `VirtualAPI` interface defines the contract for the OpenAI API call, which includes a `convert` function that takes the text, source language, and target language as input and returns the converted text and its language. +#### DescribeAction Class -The `getConfig` function returns an empty string as the configuration for this action. +Extends `SelectionAction` and utilizes the `DescribeAction_VirtualAPI` to generate descriptions for selected +code snippets within the IDE. -The `processSelection` function processes the selected text by converting it to code using the OpenAI API. It creates a `ChatProxy` instance with the `VirtualAPI` interface, the OpenAI API key, the default chat model, and the temperature setting. It then calls the `convert` function of the `VirtualAPI` with the clipboard text, "autodetect" as the source language, and the target language specified in the selection state. +##### Key Methods -The `isLanguageSupported` function checks if the given language is supported by this action. It returns `true` if the language is not `null` and not plain text (`ComputerLanguage.Text`). +- `getConfig(project: Project?)`: Returns a configuration string for the action. Currently, this method returns an empty + string. -The `isEnabled` function checks if the action should be enabled based on the current event. It returns `true` if the system clipboard contains text data and the action is enabled by the parent class (`super.isEnabled(event)`). +- `processSelection(state: SelectionState, config: String?)`: Takes the current selection state and configuration, + generates a description for the selected code, and formats it according to the code's comment style. The result is a + string that combines the generated description with the original code, properly indented and commented. -The `hasClipboard` function checks if the system clipboard contains text data by checking if the clipboard contents support the `DataFlavor.stringFlavor` or `DataFlavor.getTextPlainUnicodeFlavor` data flavors. +#### Proxy Initialization -The `getClipboard` function retrieves the text data from the system clipboard by checking if the clipboard contents support the `DataFlavor.stringFlavor` or `DataFlavor.getTextPlainUnicodeFlavor` data flavors and returning the corresponding data. +The `proxy` property lazily initializes an instance of `DescribeAction_VirtualAPI` using the `ChatProxy` class. This +setup allows for dynamic interaction with a backend service capable of generating code descriptions. The configuration +for this proxy includes settings for the AI model, temperature, and the number of retries for deserialization. + +### Usage + +To use `DescribeAction`, a user would typically select a portion of code within their IDE. The action then triggers +the `processSelection` method, which communicates with the backend service to generate a description for the selected +code. The description is formatted according to the code's comment style and inserted above the selected code snippet, +providing immediate, in-context documentation. + +### Configuration + +The behavior of `DescribeAction` can be influenced by settings in `AppSettingsState`, such as the desired human language +for descriptions, the AI model used for generating descriptions, and the temperature setting for the AI's responses. + +### Conclusion + +`DescribeAction` offers a convenient way to automatically generate descriptions for code snippets, facilitating better +documentation and understanding of code within projects. By leveraging AI through a backend service, it provides +accurate and context-aware descriptions, enhancing the development workflow. # code\InsertImplementationAction.kt -Sure, here's the documentation for the `InsertImplementationAction` class: +## Insert Implementation Action Documentation -```kotlin -/** - * An action that inserts an implementation based on a natural language specification. - * - * This action looks for a comment or selected text that describes the desired implementation. - * It then uses an AI model to generate code that implements the specified functionality. - * The generated code is inserted below the comment or selected text. - * - * The action supports various programming languages and can use the surrounding code context - * to generate more relevant implementations. - */ -class InsertImplementationAction : SelectionAction() { - - /** - * A virtual API interface for generating code implementations. - */ - interface VirtualAPI { - /** - * Generates code based on a natural language specification. - * - * @param specification The natural language specification for the desired implementation. - * @param prefix The code context or prefix for the implementation. - * @param computerLanguage The programming language for the implementation. - * @param humanLanguage The natural language used for the specification. - * @return A ConvertedText object containing the generated code and language. - */ - fun implementCode( - specification: String, - prefix: String, - computerLanguage: String, - humanLanguage: String - ): ConvertedText - - /** - * A data class representing the generated code and language. - */ - class ConvertedText { - var code: String? = null - var language: String? = null - } - } - - // ... (other methods and classes) -} -``` +### Overview + +The `InsertImplementationAction` class is part of a code generation tool designed to automatically insert code +implementations into your project. It leverages AI to generate code based on a given specification, which can be derived +from comments or selected text within your code editor. This action is integrated into an IDE environment, providing a +seamless experience for generating and inserting code. + +### Key Features + +- **AI-Powered Code Generation**: Utilizes an AI model to generate code implementations based on natural language + specifications. +- **Support for Multiple Languages**: Capable of generating code for various programming languages, excluding Text and + Markdown. +- **Context-Aware**: Takes into account the surrounding context of the selected text or comment to generate relevant + code. +- **Customizable**: Leverages project-specific settings for human and computer languages, as well as AI model + configurations. + +### How It Works -This class extends `SelectionAction` and provides an implementation for generating code based on a natural language specification. Here's a breakdown of the key components: +1. **Selection**: The action can be triggered on a specific selection within your code editor. This selection can either + be a comment or a block of code. +2. **Specification Extraction**: The tool extracts a specification from the selected text or the largest intersecting + comment. This specification is then used as input for the AI model. +3. **AI Code Generation**: The extracted specification, along with contextual information about the surrounding code, is + sent to an AI model. The model generates a code implementation based on this input. +4. **Insertion**: The generated code is automatically inserted into your codebase, directly following the selected text + or comment. + +### Usage + +To use the `InsertImplementationAction`, follow these steps: + +1. **Select Text or Comment**: In your code editor, select a block of text or a comment that describes the functionality + you wish to implement. +2. **Trigger Action**: Trigger the `InsertImplementationAction` through your IDE's action or shortcut mechanism. +3. **Review and Save**: The generated code will be inserted automatically. Review the inserted code and make any + necessary adjustments before saving your file. + +### Requirements + +- The action requires an IDE environment that supports the integration of custom actions. +- A configured AI model and API key are necessary for code generation. These can be set up in the project's settings. + +### Supported Languages + +The `InsertImplementationAction` supports various programming languages for code generation. However, it does not +support generating code for Text or Markdown files. + +### Configuration + +Project-specific configurations, such as the preferred human and computer languages and AI model settings, can be +adjusted in the project's settings. These settings influence the behavior of the code generation process. + +### Conclusion + +The `InsertImplementationAction` offers a powerful way to accelerate the development process by automatically generating +and inserting code implementations. By leveraging AI and understanding the context of your project, it provides relevant +and customizable code snippets, enhancing productivity and code quality. + +# code\RecentCodeEditsAction.kt -1. `VirtualAPI` interface: This interface defines a contract for generating code implementations. The `implementCode` function takes a natural language specification, code context/prefix, programming language, and human language as input, and returns a `ConvertedText` object containing the generated code and language. +## Recent Code Edits Action -2. `getProxy()` function: This function creates an instance of the `VirtualAPI` interface using the `ChatProxy` class from the `com.simiacryptus.jopenai.proxy` package. It configures the proxy with the appropriate API, model, temperature, and deserialization retries. +### Overview -3. `getConfig()` function: This function is required by the `SelectionAction` interface and returns an empty string, as no additional configuration is needed for this action. +The `RecentCodeEditsAction` is an IntelliJ IDEA plugin component that provides users with a dynamic action group listing +their most recent custom code edits. This feature enhances the development environment by allowing quick access and +reapplication of frequently used custom edits, streamlining the coding process. -4. `defaultSelection()` and `editSelection()` functions: These functions are responsible for determining the initial selection range and editing the selection range, respectively. They look for comments or other relevant code elements to determine the selection range. +### Features -5. `processSelection()` function: This is the main function that processes the selected text or comment and generates the code implementation. It extracts the natural language specification from the selected text or comment, retrieves the code context (if available), and calls the `implementCode` function from the `VirtualAPI` to generate the code implementation. The generated code is then inserted below the selected text or comment. +- **Dynamic Listing**: Displays a list of the most recent custom code edits as individual actions. +- **Quick Access**: Enables users to quickly reapply a recent edit from the list. +- **Visibility Control**: The action group is only visible and enabled when applicable, ensuring a clutter-free + environment. -6. `getPsiClassContextActionParams()` function: This function retrieves the selection start and end offsets, as well as the largest intersecting comment, for use in the `processSelection()` function. +### Usage -7. `isLanguageSupported()` function: This function checks if the current programming language is supported by the action. It returns `false` for plain text, Markdown, or if the language is `null`. +#### Activation Conditions -8. `PsiClassContextActionParams` class: This is a data class used to hold the selection start and end offsets, as well as the largest intersecting comment. +- The action group becomes visible and enabled only when there is a selection in the editor, and the current file is + recognized as a programming language file (not plain text). +- It is context-sensitive and tailored to enhance productivity by providing relevant actions based on the user's recent + activities. -Overall, this action provides a convenient way to generate code implementations based on natural language specifications within an Integrated Development Environment (IDE) or code editor. +#### Accessing Recent Edits + +1. **Selection Requirement**: Ensure that you have selected a portion of code in your editor. The action group is + context-sensitive and requires a selection to operate. +2. **Navigate to Action**: Access the `RecentCodeEditsAction` from the designated menu or action search in IntelliJ + IDEA. +3. **Choose an Edit**: A list of recent custom edits will be displayed, each prefixed with a number for easy + identification. If the list contains fewer than ten items, they will be prefixed with an underscore and the item + number (e.g., `_1: YourRecentEdit`). For ten or more items, they will be listed simply with the number ( + e.g., `10: YourRecentEdit`). +4. **Apply an Edit**: Click on the desired edit to apply it to the current selection. + +### Customization + +The actions listed are dynamically generated based on the user's recent custom code edits, ensuring that the most +relevant and frequently used edits are easily accessible. This list is managed through the `AppSettingsState` +configuration, where the history of commands is maintained. + +### Limitations + +- The action group is not available for plain text files, as it is designed to support programming languages recognized + by IntelliJ IDEA. +- The visibility and availability of the action group depend on the current context, specifically requiring a text + selection within the editor. + +### Conclusion + +The `RecentCodeEditsAction` enhances the IntelliJ IDEA development environment by providing a streamlined way to access +and reapply frequently used custom code edits. By integrating this feature, developers can significantly reduce the time +spent on repetitive coding tasks, focusing more on creative and complex aspects of their projects. # code\RenameVariablesAction.kt -Sure, here's the documentation for the `RenameVariablesAction` class: +## Rename Variables Action Documentation -```kotlin -/** - * An action that suggests and applies variable name renames in the selected code. - * - * This action uses an AI model to suggest better variable names for the selected code. - * The user can then choose which variable names to rename, and the action will apply - * the selected renames to the code. - * - * @property proxy The proxy object used to communicate with the AI model for suggesting renames. - */ -open class RenameVariablesAction : SelectionAction() { - - /** - * An interface defining the API for suggesting variable renames. - */ - interface RenameAPI { - /** - * Suggests variable renames for the given code. - * - * @param code The code for which to suggest variable renames. - * @param computerLanguage The programming language of the code. - * @param humanLanguage The human language to use for the suggestions. - * @return A response containing the suggested renames. - */ - fun suggestRenames( - code: String, - computerLanguage: String, - humanLanguage: String - ): SuggestionResponse - - /** - * A data class representing the response from the rename suggestion API. - * - * @property suggestions A list of suggested renames. - */ - class SuggestionResponse { - var suggestions: MutableList = mutableListOf() - - /** - * A data class representing a single suggested rename. - * - * @property originalName The original variable name. - * @property suggestedName The suggested variable name. - */ - class Suggestion { - var originalName: String? = null - var suggestedName: String? = null - } - } - } - - /** - * The proxy object used to communicate with the AI model for suggesting renames. - */ - val proxy: RenameAPI - get() = /* ... */ - - /** - * Returns an empty string as the configuration for this action. - */ - override fun getConfig(project: Project?): String = "" - - /** - * Processes the selected code and applies the chosen variable renames. - * - * @param event The action event. - * @param state The selection state containing the selected code and language. - * @param config The configuration for this action (unused). - * @return The code with the chosen variable renames applied. - */ - override fun processSelection(event: AnActionEvent?, state: SelectionState, config: String?): String { - // Get rename suggestions from the AI model - val renameSuggestions = /* ... */ - - // Let the user choose which renames to apply - val selectedSuggestions = choose(renameSuggestions) - - // Apply the chosen renames to the selected code - return /* ... */ - } - - /** - * Displays a dialog for the user to choose which variable renames to apply. - * - * @param renameSuggestions A map of original variable names to suggested names. - * @return A set of original variable names for which to apply the suggested renames. - */ - open fun choose(renameSuggestions: Map): Set { - return /* ... */ - } - - /** - * Checks if the action supports the given programming language. - * - * @param computerLanguage The programming language to check. - * @return `true` if the language is supported, `false` otherwise. - */ - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean = - computerLanguage != ComputerLanguage.Text -} -``` +### Overview + +The `RenameVariablesAction` class is an extension of the `SelectionAction` class designed to facilitate the renaming of +variables in code. It leverages an AI-based suggestion system to propose new names for variables, aiming to improve code +readability and maintainability. + +### Key Components + +#### RenameAPI Interface -This class extends the `SelectionAction` class and provides functionality for suggesting and applying variable renames to the selected code. The `RenameAPI` interface defines the API for suggesting renames, and the `proxy` property provides an instance of this API. +- **Purpose**: Defines the contract for suggesting new names for variables. +- **Method**: `suggestRenames(code: String, computerLanguage: String, humanLanguage: String)`: Accepts the current code + snippet, the programming language of the code, and the human language for the suggestions. It returns + a `SuggestionResponse` containing a list of suggested renames. -The `processSelection` function is the main entry point for the action. It gets rename suggestions from the AI model, displays a dialog for the user to choose which renames to apply, and then applies the chosen renames to the selected code. +#### SuggestionResponse Class -The `choose` function is responsible for displaying the dialog and allowing the user to select which variable renames to apply. +- **Purpose**: Encapsulates the response from the rename suggestion API. +- **Attributes**: + - `suggestions`: A mutable list of `Suggestion` objects. -The `isLanguageSupported` function checks if the action supports the given programming language, returning `true` for all languages except plain text. +#### Suggestion Class -Overall, this class provides a convenient way for users to improve the variable naming in their code with the help of an AI model. +- **Purpose**: Represents a single rename suggestion. +- **Attributes**: + - `originalName`: The original variable name. + - `suggestedName`: The suggested new name for the variable. + +### Usage + +1. **Initialization**: The `RenameVariablesAction` class is instantiated as part of the plugin's action system. +2. **Configuration**: Override the `getConfig` method if you need to provide specific configurations for the action. By + default, it returns an empty string. +3. **Processing Selection**: The `processSelection` method is the core of the action. It: + - Retrieves rename suggestions for the selected text in the code editor. + - Displays a dialog for the user to choose which suggestions to apply. + - Applies the selected renames to the text. +4. **Choosing Suggestions**: The `choose` method displays a checkbox dialog with the suggested renames, allowing users + to select which renames to apply. + +### Supported Languages + +The action supports all programming languages except plain text (`ComputerLanguage.Text`). The support is determined by +the `isLanguageSupported` method. + +### Integration + +This action is designed to be integrated into the IntelliJ IDEA platform. It utilizes the platform's action system and +UI tools for displaying dialogs and processing text selections. + +### Example + +When a user selects a block of code and triggers the `RenameVariablesAction`, the action will: + +- Analyze the selected code to identify variable names. +- Use the `RenameAPI` to get suggestions for renaming these variables based on the code's and user's language. +- Present the user with a dialog to select which variables to rename. +- Apply the selected renames to the code. + +This action streamlines the process of renaming variables, making code more readable and maintainable with minimal +effort from the user. # dev\AppServer.kt -Sure, here's the documentation for the provided code: +## AppServer Documentation + +### Overview + +The `AppServer` class is a core component designed to manage and serve web applications within a development +environment. It facilitates the dynamic addition of applications, handling their web contexts, and managing a web server +instance. This class is particularly useful for projects that require running and testing multiple web applications +simultaneously. + +### Features + +- **Dynamic Application Management:** Allows adding and removing web applications dynamically without needing to restart + the server manually. +- **WebSocket Support:** Integrated support for WebSocket applications, enabling real-time bi-directional communication + between clients and the server. +- **Progress Monitoring:** Includes functionality to monitor the server's running state and gracefully handle shutdowns + or restarts. + +### Key Components + +- **Server Instance:** A Jetty server instance configured to listen on a specified port and address. +- **Application Registry:** A registry for managing the active web applications (ChatServer instances) and their paths. +- **Web Context Management:** Handles the creation and configuration of web contexts for each registered application. + +### Usage + +#### Starting the Server + +To start the server, simply call the `start()` method. This initializes the server (if not already running) and begins +listening for incoming connections on the configured port and address. ```kotlin -package com.github.simiacryptus.aicoder.actions.dev - -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.simiacryptus.skyenet.webui.chat.ChatServer -import org.eclipse.jetty.server.Server -import org.eclipse.jetty.server.handler.ContextHandlerCollection -import org.eclipse.jetty.webapp.WebAppContext -import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer -import org.slf4j.LoggerFactory -import java.net.InetSocketAddress - -/** - * This class represents an application server that can host multiple ChatServer instances. - * It uses the Jetty server to run the ChatServer instances as web applications. - * - * @param localName The hostname or IP address to bind the server to. - * @param port The port number to listen on. - * @param project The IntelliJ project associated with this server (can be null). - */ -class AppServer( - private val localName: String, - private val port: Int, - project: Project? -) { - // ... (code omitted for brevity) ... - - /** - * Adds a new ChatServer instance to the server. - * - * @param path The context path for the ChatServer instance. - * @param socketServer The ChatServer instance to add. - */ - @Synchronized - fun addApp(path: String, socketServer: ChatServer) { - // ... (code omitted for brevity) ... - } - - /** - * Creates a new WebAppContext for the given ChatServer instance. - * - * @param server The ChatServer instance. - * @param path The context path for the ChatServer instance. - * @return The created WebAppContext. - */ - private fun newWebAppContext(server: ChatServer, path: String): WebAppContext { - // ... (code omitted for brevity) ... - } - - // ... (code omitted for brevity) ... - - companion object { - /** - * Gets the singleton instance of the AppServer. - * - * @param project The IntelliJ project associated with the server (can be null). - * @return The AppServer instance. - */ - fun getServer(project: Project?): AppServer { - // ... (code omitted for brevity) ... - } - - /** - * Stops and cleans up the singleton instance of the AppServer. - */ - fun stop() { - // ... (code omitted for brevity) ... - } - } -} +val project: Project? = // Obtain your IntelliJ Project instance +val appServer = AppServer("localhost", 8080, project) +appServer.start() +``` + +#### Adding Applications + +Applications can be added dynamically using the `addApp(path: String, socketServer: ChatServer)` method. This method +registers the application and its web context, making it accessible at the specified path. + +```kotlin +val chatServer = ChatServer() // Your ChatServer instance +appServer.addApp("/chat", chatServer) ``` -This code defines an `AppServer` class that is responsible for hosting multiple instances of `ChatServer` as web applications using the Jetty server. The `AppServer` class has the following main components: +#### Stopping the Server -1. **Constructor**: The constructor takes three parameters: `localName` (the hostname or IP address to bind the server to), `port` (the port number to listen on), and `project` (the IntelliJ project associated with the server, which can be null). +To stop the server, call the `stop()` method. This method stops the server and clears any registered applications, +preparing the server for a clean shutdown. -2. **addApp()**: This method allows you to add a new `ChatServer` instance to the server. It takes two parameters: `path` (the context path for the `ChatServer` instance) and `socketServer` (the `ChatServer` instance to add). +```kotlin +AppServer.stop() +``` + +### Singleton Access + +The `AppServer` class provides a singleton access pattern through its companion object, allowing for easy management of +a single server instance across the application. -3. **newWebAppContext()**: This private method creates a new `WebAppContext` for the given `ChatServer` instance. It configures the `WebAppContext` with the necessary settings, such as the base resource, class loader, context path, and welcome files. +- **Get Server:** `AppServer.getServer(project: Project?)` returns the current server instance, starting it if + necessary. +- **Stop Server:** `AppServer.stop()` stops the current server instance and clears it. -4. **Companion Object**: The companion object provides two static methods: - - `getServer()`: This method returns the singleton instance of the `AppServer`. If the instance doesn't exist or the server is not running, it creates a new instance and starts it. - - `stop()`: This method stops and cleans up the singleton instance of the `AppServer`. +### Important Considerations -The `AppServer` class also includes some helper methods and fields for managing the server lifecycle, handling progress indicators, and logging. +- The server automatically restarts upon adding a new application to reflect the updated context. Ensure that this + behavior is accounted for in your application logic. +- The server uses lazy initialization for performance optimization and to avoid unnecessary resource allocation. -Overall, this code provides a way to host multiple `ChatServer` instances as web applications within a single Jetty server instance. It allows you to dynamically add or remove `ChatServer` instances and manage the server lifecycle. +### Conclusion + +The `AppServer` class offers a flexible and efficient way to manage web applications and their server contexts within a +development environment. Its dynamic application management, WebSocket support, and progress monitoring capabilities +make it a valuable tool for developers working on web-based projects. # dev\PrintTreeAction.kt -Sure, here's the documentation for the `PrintTreeAction` class: +## PrintTreeAction User Guide + +### Overview + +The `PrintTreeAction` is a powerful tool integrated into the IntelliJ IDE, designed for developers who need to visualize +the structure of their code files in a tree format. This action is particularly useful for understanding the +organization and hierarchy of classes, methods, and other elements within a file. + +### Prerequisites + +Before you can use the `PrintTreeAction`, ensure the following: + +- You have IntelliJ IDE installed. +- The "devActions" setting is enabled in your project's `AppSettingsState`. + +### How to Use PrintTreeAction + +1. **Open the Desired File**: Navigate to and open the file you wish to analyze in IntelliJ. +2. **Access the Action**: Right-click within the editor window to open the context menu. Look for the "PrintTreeAction" + option. If you do not see this option, ensure you have met all prerequisites. +3. **Execute the Action**: Click on "PrintTreeAction". The action will process the currently open file. +4. **View the Results**: The tree structure of the file will be printed to the IntelliJ log. You can access this log at + the bottom of the IntelliJ window, typically in the "Run" or "Debug" tabs. + +### Features + +- **Tree Structure Visualization**: Quickly understand the hierarchical structure of your PsiFile, including classes, + methods, and other code elements. +- **Easy Access**: Available directly from the editor's context menu, allowing for seamless integration into your + development workflow. +- **Conditional Availability**: This action is only available when the "devActions" setting is enabled, preventing + accidental usage in non-development environments. + +### Troubleshooting + +- **Action Not Visible**: If the "PrintTreeAction" is not visible in the context menu, ensure that the "devActions" + setting is enabled in your `AppSettingsState`. +- **Null Pointer Exceptions**: Ensure the file you are trying to analyze is fully loaded and not corrupted to avoid null + pointer exceptions during the action's execution. + +### Conclusion + +The `PrintTreeAction` is an invaluable tool for developers looking to gain insights into the structure of their code +files. By following the steps outlined in this guide, you can efficiently utilize this action to enhance your +development process within the IntelliJ IDE. + +# FileContextAction.kt + +## FileContextAction Documentation + +### Overview + +`FileContextAction` is an abstract class designed to extend the functionality of actions within a specific file or +folder context in an IntelliJ platform-based IDE. It allows developers to create actions that can process selected files +or folders, perform operations based on those selections, and integrate seamlessly with the IDE's UI and file system. + +### Key Features + +- **Flexible File and Folder Support**: Actions can be configured to support either files, folders, or both, depending + on the needs of the specific action being implemented. +- **Configurable Processing**: Implementers can define custom processing logic for selected files or folders, allowing + for a wide range of operations such as file generation, modification, or analysis. +- **IDE Integration**: Utilizes the IntelliJ platform's UI and file system APIs for selecting files/folders, displaying + notifications, and managing file operations within the IDE environment. +- **Asynchronous Execution**: Operations are performed in a separate thread, ensuring that the IDE remains responsive + during potentially time-consuming file processing tasks. + +### Usage + +To use `FileContextAction`, you need to create a subclass and implement the abstract methods. Here's a simplified +example: ```kotlin -/** - * The PrintTreeAction class is an IntelliJ action that enables developers to print the tree structure of a PsiFile. - * To use this action, follow these steps: - * - * 1. Make sure that the "devActions" setting is enabled in the plugin's settings. - * 2. Open the file you want to print the tree structure of in the IntelliJ editor. - * 3. Right-click in the editor and select the "PrintTreeAction" option from the context menu. - * - * This action will print the tree structure of the currently open file to the log. - * - * @see BaseAction The base class for this action. - * @see AppSettingsState The class that manages the plugin's settings. - * @see PsiUtil A utility class for working with the IntelliJ PSI (Program Structure Interface). - */ -class PrintTreeAction : BaseAction() { - - /** - * Handles the action event by printing the tree structure of the largest contained entity - * (e.g., file, class, method) to the log. - * - * @param e The action event. - */ - override fun handle(e: AnActionEvent) { - log.warn(PsiUtil.printTree(PsiUtil.getLargestContainedEntity(e)!!)) - } - - /** - * Checks if the action is enabled based on the "devActions" setting in the plugin's settings. - * - * @param event The action event. - * @return True if the "devActions" setting is enabled, false otherwise. - */ - override fun isEnabled(event: AnActionEvent): Boolean { - return AppSettingsState.instance.devActions - } - - companion object { - private val log = LoggerFactory.getLogger(PrintTreeAction::class.java) - } +class MyFileAction : FileContextAction() { + override fun processSelection(state: SelectionState, config: MyConfig?): Array { + // Implement your file processing logic here + return arrayOf() // Return an array of files that were processed or generated + } + + override fun getConfig(project: Project?, e: AnActionEvent): MyConfig? { + // Optionally, provide configuration for the action based on the project or event context + return MyConfig() + } } ``` -This documentation explains the purpose of the `PrintTreeAction` class, how to use the action, and provides details about the class members and their responsibilities. It also includes cross-references to related classes and utilities used by the action. +#### Implementing `processSelection` + +This method is where the main logic of your action should be implemented. It receives a `SelectionState` object +containing the selected file or folder and the project root directory. You can use this information to perform your +desired file operations. + +#### Configuring Your Action + +The `getConfig` method allows you to provide custom configuration for your action, which can be useful for tailoring its +behavior based on the project context or user preferences. + +### Integration Points + +- **isEnabled**: Determines whether the action is enabled based on the current context, such as the type of file + selected or project settings. +- **handle**: The entry point for the action's execution. It sets up the necessary context and invokes + the `processSelection` method. + +### Best Practices + +- Ensure that your file operations are efficient and handle potential errors gracefully to avoid disrupting the user's + workflow. +- Use the provided IDE APIs for UI interactions and file system operations to ensure compatibility and a consistent user + experience. + +### Conclusion + +`FileContextAction` provides a powerful framework for extending the functionality of IntelliJ platform-based IDEs with +custom file and folder actions. By implementing the abstract methods and following the best practices, developers can +create sophisticated tools that enhance the development experience. # dev\InternalCoderAction.kt -Sure, here's the documentation for the `InternalCoderAction` class: +## InternalCoderAction Documentation -```kotlin -/** - * An action that launches an internal coding agent within the IntelliJ IDE. - * - * This action creates a new session for the coding agent and initializes it with the current - * context information from the IDE, such as the current editor, file, project, and symbols. - * It then starts a web server and opens a browser window to interact with the coding agent. - * - * The coding agent is an instance of [CodingAgent] and is configured with the specified API, - * data storage, session, user, UI, interpreter, symbols, temperature, details, and model. - * - * When the user sends a message to the coding agent, the [userMessage] function of the - * [ApplicationServer] is called, which starts the coding agent with the user's message. - * - * @property path The path for the internal coding agent's web server. - */ -class InternalCoderAction : BaseAction() { - // ... - - /** - * Handles the action event by launching the internal coding agent. - * - * @param e The action event. - */ - override fun handle(e: AnActionEvent) { - // ... - } - - /** - * Determines whether the action is enabled based on the development settings. - * - * @param event The action event. - * @return `true` if the action is enabled, `false` otherwise. - */ - override fun isEnabled(event: AnActionEvent): Boolean { - // ... - } - - companion object { - // ... - - /** - * Initializes the application server for the internal coding agent. - * - * @param server The app server instance. - * @param path The path for the internal coding agent's web server. - * @return The initialized [ApplicationServer] instance. - */ - private fun initApp(server: AppServer, path: String): ApplicationServer { - // ... - } - } -} -``` +### Overview -This class extends `BaseAction` and provides an implementation for the `handle` function, which is responsible for launching the internal coding agent. It creates a new session, initializes the coding agent with the current context information, starts a web server, and opens a browser window to interact with the agent. +The `InternalCoderAction` class is part of a plugin designed to integrate coding assistance directly into the IntelliJ +IDE. It facilitates the creation of a coding session within the IDE, leveraging an internal coding agent to provide +suggestions and enhancements to the user's coding experience. This action is triggered through the IDE's action system +and is intended for developers looking for an integrated coding assistant. -The `isEnabled` function checks if the development actions are enabled in the app settings before allowing the action to be executed. +### Features -The `initApp` function is a companion object function that initializes the `ApplicationServer` for the internal coding agent. It creates a new instance of `ApplicationServer` if it doesn't already exist and registers it with the app server. +- **Session Initialization**: Creates a unique session for each coding instance, ensuring personalized and isolated + coding assistance. +- **Dynamic Symbol Resolution**: Collects and resolves symbols from the current editor context, including the editor, + file, element, and project, to provide context-aware coding assistance. +- **Coding Agent Integration**: Utilizes a `CodingAgent` to process coding requests and provide suggestions based on the + current context and user input. +- **Web UI Support**: Opens a browser window pointing to the coding session's UI, allowing for an interactive coding + assistance experience. +- **Customizable Assistance**: Supports customization of the coding agent's behavior, including the response temperature + and operational details. -The `ApplicationServer` instance overrides the `userMessage` function to start the coding agent with the user's message when a message is received. It also provides the root directory for the coding agent's data storage. +### Usage -# FileContextAction.kt +1. **Prerequisites**: Ensure that the plugin is installed and enabled in your IntelliJ IDE. The feature is available + only if the development actions are enabled in the application settings (`AppSettingsState.instance.devActions`). -Sure, here's the documentation for the `FileContextAction` class: +2. **Triggering the Action**: The action can be triggered through the IDE's action system, typically via a menu item or + keyboard shortcut specific to the plugin. -The `FileContextAction` is an abstract class that extends `BaseAction` and provides a base implementation for actions that operate on files or folders in the current project. It defines two abstract methods that subclasses must implement: +3. **Coding Session**: Once triggered, the action initializes a new coding session, setting up the necessary environment + and context for the coding agent to operate. -1. `processSelection(state: SelectionState, config: T?): Array`: This method is responsible for processing the selected file or folder and returning an array of generated files. +4. **Interaction**: Interact with the coding agent through the opened web UI or directly within the IDE, depending on + the implementation details of the plugin. -2. `getConfig(project: Project?, e: AnActionEvent): T?`: This method returns an optional configuration object of type `T` that can be used by the `processSelection` method. +5. **Session Closure**: The session remains active until manually closed or terminated by the user or the system. -The `FileContextAction` class also provides the following functionality: +### Configuration -- It handles the action execution by retrieving the selected file or folder, calling the `processSelection` method, and opening the generated files in the IDE. -- It supports both file and folder selections, controlled by the `supportsFiles` and `supportsFolders` constructor parameters. -- It provides a `SelectionState` data class that encapsulates the selected file or folder and the project root directory. -- It includes a utility method `open(project: Project, outputPath: Path)` that opens a generated file in the IDE. This method uses a scheduled thread pool to periodically check if the file exists and is ready to be opened. -- It has an `isDevAction` property that can be used to enable or disable the action based on the user's development mode settings. +- **Development Actions**: Enable or disable development actions through the `AppSettingsState` configuration. +- **Session Parameters**: Customize session parameters such as the response temperature and operational details directly + within the `InternalCoderAction` class or through external configuration options. -The `FileContextAction` class also includes a companion object with a logger instance and the `open` method implementation. +### Troubleshooting -To create a new action that extends `FileContextAction`, you need to implement the `processSelection` and `getConfig` methods. The `processSelection` method should perform the desired file or folder processing and return an array of generated files. The `getConfig` method can return an optional configuration object that will be passed to the `processSelection` method. +- **Browser Opening Failure**: If the system encounters an issue opening the browser automatically, check the system's + default browser settings and ensure that the IDE has the necessary permissions. +- **Session Initialization Error**: Ensure that the plugin's server component (`AppServer`) is running and accessible. + Check the IDE's log files for any error messages related to the plugin. -Here's an example of how you might implement a subclass of `FileContextAction`: +### Conclusion -```kotlin -class MyFileAction : FileContextAction() { +The `InternalCoderAction` provides a seamless integration of coding assistance within the IntelliJ IDE, enhancing the +development experience through context-aware suggestions and interactive coding sessions. By leveraging advanced coding +agents and a dedicated UI, developers can improve their coding efficiency and quality directly within their preferred +development environment. - override fun processSelection(state: SelectionState, config: MyConfig?): Array { - // Perform file or folder processing based on the selected file/folder and configuration - val generatedFiles = mutableListOf() - // ... add generated files to the list - return generatedFiles.toTypedArray() - } +# generic\AppendTextWithChatAction.kt - override fun getConfig(project: Project?, e: AnActionEvent): MyConfig? { - // Return a configuration object or null if no configuration is needed - return MyConfig(/* ... */) - } +## AppendTextWithChatAction Documentation -} -``` +### Overview -In this example, `MyFileAction` is a subclass of `FileContextAction` that takes a custom configuration object `MyConfig`. The `processSelection` method performs the desired file or folder processing and returns an array of generated files. The `getConfig` method returns an instance of `MyConfig` or `null` if no configuration is needed. +The `AppendTextWithChatAction` class is a specialized action designed to append text to the end of a user's selected text within an +IDE environment. It leverages OpenAI's language model to generate contextually relevant text based on the user's +selection. -# generic\AppendAction.kt +### How It Works -Sure, here's the documentation for the `AppendAction` class: +1. **Configuration Retrieval**: Initially, the action retrieves any necessary configuration from the project settings, + though in its current implementation, it returns an empty string as it does not require specific configuration. -```kotlin -/** - * An action that appends text to the end of the user's selected text using OpenAI's chat model. - * - * This action is a subclass of `SelectionAction`, which means it operates on a selected text - * and returns a `String` as the result. - * - * When the action is executed, it creates a `ChatRequest` with the following properties: - * - The model specified in the app settings - * - The temperature specified in the app settings - * - Two messages: - * 1. A system message instructing the model to append text to the user's prompt - * 2. A user message containing the selected text - * - * The action then sends the `ChatRequest` to the OpenAI API and retrieves the response. - * The response is then processed to append the generated text to the end of the selected text. - * If the generated text starts with the selected text, the duplicated portion is removed. - * - * The `getConfig` method is overridden to return an empty string, as this action does not require - * any additional configuration. - */ -class AppendAction : SelectionAction() { - /** - * Returns an empty string, as this action does not require any additional configuration. - */ - override fun getConfig(project: Project?): String { - return "" - } - - /** - * Processes the selected text by appending text generated by the OpenAI chat model. - * - * @param state The selection state containing the selected text. - * @param config Not used in this action. - * @return The selected text with the generated text appended to the end. - */ - override fun processSelection(state: SelectionState, config: String?): String { - val settings = AppSettingsState.instance - val request = ChatRequest( - model = settings.defaultChatModel().modelName, - temperature = settings.temperature - ).copy( - temperature = settings.temperature, - messages = listOf( - ChatMessage(Role.system, "Append text to the end of the user's prompt".toContentList(), null), - ChatMessage(Role.user, state.selectedText.toString().toContentList(), null) - ), - ) - val chatResponse = api.chat(request, settings.defaultChatModel()) - val b4 = state.selectedText ?: "" - val str = chatResponse.choices[0].message?.content ?: "" - return b4 + if (str.startsWith(b4)) str.substring(b4.length) else str - } -} -``` +2. **Processing Selection**: The core functionality resides in the `processSelection` method, where it performs the + following steps: + - Retrieves the application's settings, particularly focusing on the default chat model and temperature settings for + the OpenAI API request. + - Constructs a `ChatRequest` object with the model and temperature settings, and includes two messages: + - A system message indicating the action to be performed ("Append text to the end of the user's prompt"). + - A user message containing the selected text. + - Sends the request to the OpenAI API and receives a chat response. + - Appends the generated text to the original selected text, ensuring no duplication of the initial selection. -This documentation explains the purpose of the `AppendAction` class, its inheritance from `SelectionAction`, and the details of how it creates and processes the `ChatRequest` to append text to the selected text using the OpenAI chat model. It also documents the `getConfig` and `processSelection` methods, explaining their roles and parameters. +### Requirements -# generic\AnalogueFileAction.kt +- **IntelliJ Platform**: This action is designed to work within the IntelliJ platform, requiring a project context to + operate. +- **AppSettingsState**: The action depends on `AppSettingsState` for retrieving application-wide settings, such as the + default chat model and temperature for API requests. -Sure, here's the documentation for the `AnalogueFileAction` class: +### Usage -```kotlin -/** - * An action that generates a new file based on a user-provided directive and an existing file's code. - * The new file is created in the same directory as the existing file, with a unique filename if necessary. - * After generating the file, it is opened in the IDE. - */ -class AnalogueFileAction : FileContextAction() { - - /** - * Checks if the action is enabled for the current event. - * The action is disabled if the selected file is a directory. - */ - override fun isEnabled(event: AnActionEvent): Boolean { ... } - - /** - * Data class representing a project file with its path and code content. - */ - data class ProjectFile( - val path: String = "", - val code: String = "" - ) - - /** - * UI class for displaying the directive input field. - */ - class SettingsUI { ... } - - /** - * User settings data class for storing the directive. - */ - class UserSettings( - var directive: String = "", - ) - - /** - * Settings data class for storing the user settings and the current project. - */ - class Settings( - val settings: UserSettings? = null, - val project: Project? = null - ) - - /** - * Gets the configuration for the action by showing a dialog to the user. - */ - override fun getConfig(project: Project?, e: AnActionEvent): Settings { ... } - - /** - * Processes the selected file by generating a new file based on the directive and the existing file's code. - * Returns an array containing the generated file. - */ - override fun processSelection(state: SelectionState, config: Settings?): Array { ... } - - /** - * Generates a new file based on the provided base file and directive. - */ - private fun generateFile(baseFile: ProjectFile, directive: String): ProjectFile { ... } - - companion object { - /** - * Opens the generated file in the IDE. - */ - fun open(project: Project, outputPath: Path) { ... } - - /** - * Gets the module root directory for the given file by searching for the nearest `.git` directory. - */ - fun getModuleRootForFile(file: File): File { ... } - } -} -``` +To use the `AppendTextWithChatAction`, ensure it is properly integrated into your IntelliJ platform-based application or plugin. It +does not require manual configuration but relies on the application's settings for the OpenAI API parameters. + +When triggered, it will automatically append contextually generated text to the user's selected text, enhancing or +completing their input based on the model's understanding and the provided prompt. + +### Limitations + +- **Configuration**: Currently, the `getConfig` method does not utilize project-specific configurations and returns an + empty string. +- **Context Sensitivity**: The effectiveness of the appended text depends on the accuracy of the OpenAI model's + understanding of the selected text and the provided prompt. + +### Conclusion + +The `AppendTextWithChatAction` offers a convenient way to extend user input with AI-generated text, seamlessly integrating with the +IntelliJ platform. By leveraging OpenAI's language models, it provides a powerful tool for enhancing user productivity +and creativity within the development environment. + +# generic\GenerateRelatedFileAction.kt + +## Analogue File Action Documentation + +### Overview + +The Analogue File Action is a feature designed for IntelliJ-based IDEs that assists developers in automatically +generating new files based on existing ones, with modifications guided by user-provided directives. This action +leverages the power of AI to interpret directives and apply them to the selected file, creating a new, analogous file +that meets the specified requirements. + +### Features + +- **Context-Sensitive Activation**: The action is only enabled for non-directory files, ensuring it is contextually + relevant. +- **Customizable Directives**: Users can input natural language directives to guide the creation of the new file. +- **AI-Powered Processing**: Utilizes an AI model to interpret directives and generate the new file content. +- **Automatic File Naming and Placement**: Generates a unique file name and path to avoid conflicts, placing the new + file relative to the project root. +- **IDE Integration**: Automatically opens the newly created file in the IDE for immediate review and editing. + +### How to Use + +1. **Select a File**: In your project, select the file you want to base your new file on. +2. **Activate the Action**: Right-click and find the "Create Analogue File" option. This option is only available for + non-directory files. +3. **Enter Directive**: In the popup dialog, enter your directive in the provided text area. This directive should + describe how you want the new file to differ from the selected one. +4. **Generate File**: Click "OK" to generate the new file. The AI will process your directive, create the new file, and + place it in an appropriate location within your project structure. +5. **Review and Edit**: The new file will automatically open in your IDE. Review the generated content and make any + necessary adjustments. + +### Settings + +- **Directive**: A JTextArea where you input your natural language instructions for generating the new file. + +### Technical Details + +- **Settings Storage**: User settings, including the directive, are stored in a `UserSettings` class instance. +- **File Generation**: The `generateFile` method processes the base file and directive, interacting with an AI model to + produce the new file content and path. +- **File Handling**: The action ensures the new file does not overwrite existing files by checking for conflicts and + adjusting the file name as necessary. +- **IDE Integration**: Utilizes IntelliJ platform APIs for file operations and UI interactions, ensuring a seamless + experience within the IDE. + +### Requirements + +- IntelliJ-based IDE (e.g., IntelliJ IDEA, PyCharm) +- Java Development Kit (JDK) + +### Installation + +This feature is packaged as part of a specific IntelliJ plugin. Install the plugin from the JetBrains Marketplace or +your IDE's plugin settings panel. + +### Support + +For issues, feature requests, or contributions, please refer to the project's GitHub repository or contact the +development team through the appropriate channels. + +# generic\MultiStepPatchAction.kt + +## MultiStepPatchAction Documentation + +### Overview + +The `MultiStepPatchAction` class is part of a system designed to automate development tasks within a project. It integrates +with an IDE to provide a user-friendly interface for automating code modifications, leveraging AI models to interpret +user requests and generate actionable development tasks. + +### Key Features + +- **Automated Task Generation**: Translates user directives into a detailed action plan, breaking down requests into + manageable tasks. +- **Code Modification Suggestions**: Generates code patches in diff format, suggesting specific changes to be made in + the project files. +- **Interactive Web UI**: Opens a browser window to interact with the user, providing a session-based interface for task + management and execution. +- **Integration with AI Models**: Utilizes GPT models for understanding user requests and generating code modifications. + +### Usage + +1. **Initialization**: The action is triggered within an IDE environment, starting a new session for the user. +2. **Selecting a Project Folder**: The user selects a folder within their project. This folder's path is stored and + associated with the current session. +3. **Web UI Interaction**: A browser window is opened, directing the user to an interactive session where they can input + their development requests. +4. **Task Generation and Execution**: The system interprets the user's requests, generating a list of tasks and + suggesting code modifications to fulfill these tasks. The user can review and apply these suggestions directly from + the web UI. + +### Components + +#### AutoDevApp + +Represents the application server handling user sessions and messages. It processes user messages to generate +development tasks and code modification suggestions. + +##### Key Methods + +- `userMessage()`: Handles incoming messages from users, generating tasks and code modifications based on the content of + the message. + +#### AutoDevAgent + +Responsible for processing individual development tasks, interacting with AI models to generate code patches and +suggestions. -The `AnalogueFileAction` class extends `FileContextAction` and provides functionality to generate a new file based on a user-provided directive and an existing file's code. The user is prompted to enter a directive through a dialog, and the action then generates a new file using the OpenAI API. The generated file is created in the same directory as the existing file, with a unique filename if necessary. After generating the file, it is opened in the IDE. +##### Key Methods -The class has several nested classes: +- `start()`: Initiates the process of generating development tasks and code modifications based on the user's request. -- `ProjectFile`: A data class representing a project file with its path and code content. -- `SettingsUI`: A UI class for displaying the directive input field. -- `UserSettings`: A data class for storing the user-provided directive. -- `Settings`: A data class for storing the user settings and the current project. +### How It Works -The `generateFile` function is responsible for generating the new file using the OpenAI API. It sends a request to the API with the existing file's code and the user-provided directive, and the API generates the new file's content based on these inputs. +1. The `MultiStepPatchAction` class initiates a session and opens a web UI for user interaction. +2. The user inputs a development request in the web UI. +3. The `AutoDevApp` processes this request, utilizing `AutoDevAgent` to interact with AI models and generate a list of + actionable tasks. +4. For each task, `AutoDevAgent` suggests specific code modifications in diff format. +5. The user reviews and applies these suggestions to their project files directly from the web UI. -The `open` function in the companion object is responsible for opening the generated file in the IDE. It uses the `FileEditorManager` to open the file and refreshes the file system if necessary. +### Prerequisites -The `getModuleRootForFile` function in the companion object finds the module root directory for the given file by searching for the nearest `.git` directory. +- An IDE environment compatible with the system. +- Access to the web UI through a supported browser. -Overall, this action provides a convenient way for developers to generate new files based on existing code and natural language instructions, leveraging the power of the OpenAI API. +### Conclusion -# generic\AutoDevAction.kt +The `MultiStepPatchAction` system offers a powerful tool for automating development tasks, leveraging AI to streamline the +process of code modification. By providing a user-friendly interface and integrating with advanced AI models, it +simplifies the task management process, making it easier for developers to implement changes and enhancements to their +projects. -This code defines an IntelliJ IDEA plugin action called `AutoDevAction` that provides an interactive code development assistant powered by OpenAI's language models. Here's a breakdown of the code: +# generic\CreateFileFromDescriptionAction.kt -1. **AutoDevAction Class** - - This class extends `BaseAction` and is responsible for handling the action event triggered by the user. - - When the action is triggered, it creates a new session and initializes an `AutoDevApp` instance. - - It also starts a server and opens a web browser window pointing to the server's URL. +## CreateFileFromDescriptionAction Documentation -2. **AutoDevApp Class** - - This class extends `ApplicationServer` and handles the user's input messages. - - It defines a `Settings` data class to store the user's preferences, such as the budget, tools, and model to be used. - - The `userMessage` function is called when the user sends a message. - - It creates an `AutoDevAgent` instance and starts the code development process based on the user's message. +### Overview -3. **AutoDevAgent Class** - - This class extends `ActorSystem` and is responsible for managing the code development process. - - It defines two actors: `DesignActor` and `TaskCodingActor`. - - The `DesignActor` is responsible for translating the user's directive into an action plan (a list of tasks). - - The `TaskCodingActor` is responsible for implementing the changes to the codebase as described in the task list. - - The `start` function is the entry point for the code development process. - - It iterates over the tasks in the action plan and applies the necessary code changes using the `TaskCodingActor`. - - The code changes are displayed as diffs, and the user can apply them to the codebase. +The `CreateFileFromDescriptionAction` class is designed to automate the process of generating and creating new files within a project +based on natural language directives. It leverages the OpenAI API to interpret these directives and generate the +corresponding file content and path. This action is part of a larger system aimed at enhancing developer productivity +through automation. -4. **Companion Object** - - The companion object contains utility functions and data classes. - - The `TaskList` data class represents the action plan generated by the `DesignActor`. - - The `Task` data class represents an individual task in the action plan, including the paths of the files to be modified and a description of the changes. +### How It Works -Overall, this code provides an interactive code development assistant that can understand natural language instructions from the user, generate an action plan, and apply the necessary code changes to the codebase. It leverages OpenAI's language models and integrates with IntelliJ IDEA to provide a seamless development experience. +1. **Directive Input**: The user provides a natural language directive describing the file to be created. This can be as + simple as "Create a default log4j configuration file" or more complex, depending on the needs. + +2. **File Generation**: Based on the provided directive, the system uses the OpenAI API to generate both the content of + the file and the suggested file path relative to the project root. + +3. **File Creation**: The system then creates the file at the suggested path with the generated content. If a file with + the same name already exists, it appends a unique index to the file name to avoid overwriting. + +### Key Components + +- **ProjectFile**: A simple data class holding the path and code of the generated file. +- **SettingsUI**: A user interface component that allows the user to input the directive in a text area. +- **Settings**: Holds the directive as a string for processing. +- **processSelection**: The main function that processes the user's selection and directive, generating and creating the + file accordingly. + +### Usage + +1. **Input Directive**: Through the `SettingsUI`, the user inputs a directive describing the file they wish to create. +2. **Selection**: The user selects a file or directory within their project, which serves as a context for the file + generation. +3. **Execution**: Upon executing the action, the system processes the directive and selection, generating and creating + the new file as described. + +### Example + +If a user inputs the directive "Create a default log4j configuration file" and selects the root directory of their Java +project, the system might generate a file named `log4j.properties` with standard logging configurations, placing it in +an appropriate directory within the project. + +### Conclusion + +The `CreateFileFromDescriptionAction` class streamlines the process of creating new files within a project, guided by natural language +directives. It simplifies tasks that would otherwise require manual file creation and content generation, thereby +enhancing developer productivity. # generic\CodeChatAction.kt -Sure, here's the documentation for the `CodeChatAction` class: +## CodeChatAction Documentation -```kotlin -/** - * This class represents an action that opens a code chat session in a web browser. - * It allows the user to interact with an AI model to get assistance with the code they have open in the editor. - * - * When the action is triggered, it creates a new session ID and initializes a [CodeChatSocketManager] instance - * with the selected code, file name, and language. It then starts a web server and opens a browser window - * pointing to the code chat application. - * - * The code chat application is a web-based interface that allows the user to chat with the AI model - * and receive suggestions and explanations related to their code. - */ -class CodeChatAction : BaseAction() { - - /** - * The path where the code chat application is served. - */ - val path = "/codeChat" - - /** - * Handles the action event by creating a new code chat session and opening a browser window. - * - * @param e The action event. - */ - override fun handle(e: AnActionEvent) { - // ... (implementation details) - } - - /** - * Checks if the action is enabled for the given event. - * - * @param event The action event. - * @return `true` if the action is enabled, `false` otherwise. - */ - override fun isEnabled(event: AnActionEvent) = true - - companion object { - /** - * The logger instance for this class. - */ - private val log = LoggerFactory.getLogger(CodeChatAction::class.java) - - /** - * A map of active socket managers for code chat sessions. - */ - private val agents = mutableMapOf() - - /** - * The root directory for the code chat application. - */ - val root: File get() = File(ApplicationEvents.pluginHome, "code_chat") - - /** - * Initializes the code chat application server and registers it with the provided [AppServer]. - * - * @param server The [AppServer] instance. - * @param path The path where the code chat application is served. - * @return The initialized [ChatServer] instance. - */ - private fun initApp(server: AppServer, path: String): ChatServer { - // ... (implementation details) - } - } -} -``` +### Overview -This documentation provides an overview of the `CodeChatAction` class, its purpose, and the responsibilities of its methods and properties. It also includes documentation for the companion object and its members. +The `CodeChatAction` class is part of a plugin designed to enhance coding productivity by integrating a code chat +feature directly into your development environment. This feature allows developers to engage in discussions about code +snippets, share insights, and collaborate more effectively. -# generic\CreateFileAction.kt +### Key Features -This code defines a class `CreateFileAction` that extends `FileContextAction`. It is used to create a new file based on a natural language directive provided by the user. Here's a breakdown of the code: +- **Code Selection Sharing:** Share selected code snippets or entire files with collaborators in real-time. +- **Language Detection:** Automatically detects the programming language of the shared code for syntax highlighting and + context-aware discussions. +- **Session Management:** Creates unique sessions for each code chat, ensuring discussions are organized and easily + accessible. +- **Browser Integration:** Opens the code chat in the default web browser, providing a seamless transition from code + editor to discussion platform. -1. `CreateFileAction` class: - - Extends `FileContextAction` with `false` for `isReadOnly` and `true` for `isWritable`. - - Defines an inner class `ProjectFile` to hold the file path and code. - - Defines an inner class `Settings` to hold the user-provided directive. +### How It Works -2. `processSelection` method: - - Takes a `SelectionState` and `Settings` object as input. - - Determines the project root, module root, and relative file path based on the selected file. - - Calls the `generateFile` method to generate the new file content based on the directive. - - Constructs the output file path, ensuring it doesn't already exist. - - Creates the necessary directories and writes the generated code to the output file. - - Returns an array containing the newly created file. +1. **Initialization:** When the action is triggered, the plugin checks for an active editor and the selected text within + it. If no text is selected, the entire document's text is used. +2. **Session Creation:** A unique session ID is generated for the code chat session. This session is associated with the + selected code snippet or document, the detected programming language, and other relevant metadata. +3. **Code Chat Server:** The plugin interacts with an `AppServer` instance to register the code chat session and + initialize the necessary backend services, including a `ChatServer` for managing chat sessions. +4. **Opening the Chat:** After a brief delay to ensure server readiness, the plugin attempts to open the code chat in + the user's default web browser, directing them to the specific session URL. -3. `generateFile` method: - - Takes the base file path and the user-provided directive as input. - - Constructs a ChatRequest with instructions for generating a new file based on the directive. - - Sends the ChatRequest to the OpenAI API using the configured model and temperature settings. - - Parses the response to extract the file path and code. - - Returns a `ProjectFile` object containing the file path and code. +### Requirements -The `CreateFileAction` class is designed to be used within the context of a larger application that interacts with files and directories. It leverages the OpenAI API to generate new file content based on natural language instructions provided by the user. The generated file is created at a location relative to the selected file or project root, ensuring that it doesn't overwrite existing files. +- **IDE Support:** The plugin is designed to work within an IDE that supports the IntelliJ Platform, such as IntelliJ + IDEA. +- **Desktop Environment:** Requires a desktop environment capable of opening web URLs in a browser. -# generic\DictationAction.kt +### Usage -Sure, here's the documentation for the `DictationAction` class: +To use the `CodeChatAction`, follow these steps: -```kotlin -/** - * This class represents an action in the IntelliJ IDEA plugin that allows users to dictate text - * using speech-to-text functionality. When the action is triggered, it starts recording audio, - * processes the audio data, and transcribes the speech into text, which is then inserted into - * the currently open editor at the cursor position or replacing the selected text. - */ -class DictationAction : BaseAction() { - - /** - * This method is the entry point for the action. It sets up the necessary threads and components - * for recording audio, processing the audio data, and transcribing the speech into text. - * - * @param e The action event that triggered the action. - */ - override fun handle(e: AnActionEvent) { - // Implementation details... - } - - /** - * This inner class is responsible for transcribing the audio data into text and inserting - * the transcribed text into the editor. - * - * @property event The action event that triggered the action. - * @property audioBuffer The buffer containing the audio data to be transcribed. - * @property continueFn A function that determines whether the transcription should continue. - * @property offsetStart The initial offset in the editor where the transcribed text should be inserted. - * @property prompt The initial prompt for the speech-to-text transcription. - */ - private inner class DictationPump( - val event: AnActionEvent, - private val audioBuffer: Deque, - val continueFn: () -> Boolean, - offsetStart: Int, - var prompt: String = "" - ) { - - /** - * This method runs the transcription process. It continuously checks the audio buffer - * and transcribes the audio data into text, which is then inserted into the editor. - */ - fun run() { - // Implementation details... - } - } - - /** - * This method creates and displays a dialog window that shows the status of the dictation process. - * - * @param e1 The action event that triggered the action. - * @return The JFrame instance representing the dialog window. - */ - private fun statusDialog(e1: AnActionEvent): JFrame { - // Implementation details... - } - - /** - * This method checks if the action is enabled by attempting to get a TargetDataLine instance, - * which is required for audio recording. - * - * @param event The action event that triggered the action. - * @return True if the action is enabled, false otherwise. - */ - override fun isEnabled(event: AnActionEvent): Boolean { - // Implementation details... - } - - companion object { - // Companion object with logger and thread pool instances - } -} -``` +1. **Select Code:** In your IDE, select the code snippet you wish to discuss. +2. **Trigger Action:** Trigger the `CodeChatAction` through the designated shortcut or menu option. +3. **Engage in Discussion:** Once the code chat session opens in your browser, you can start discussing the code with + your collaborators. + +### Troubleshooting + +- **Browser Not Opening:** Ensure your default web browser is set correctly and can be launched from your desktop + environment. +- **Session Not Created:** Check your IDE's log for any errors related to the `CodeChatAction` or network issues that + may prevent session creation. + +For further assistance, consult the plugin's support resources or contact the development team. + +# generic\VoiceToTextAction.kt + +## VoiceToTextAction Plugin Documentation + +### Overview + +The VoiceToTextAction plugin is designed to enhance your coding experience by allowing you to dictate code and comments +directly into your IDE. This innovative tool captures your voice, processes the audio, and converts it into text, +inserting the transcribed text at the current cursor position or replacing the selected text in your editor. + +### Features + +- **Voice to Text Conversion**: Transcribe your voice into text directly in the IDE editor. +- **Continuous Dictation**: Dictate for as long as you need; the transcription stops when you close the status dialog. +- **Automatic Insertion**: The transcribed text is automatically inserted at the cursor's position or replaces the + selected text. +- **Background Processing**: Audio recording, processing, and transcription run in separate threads, ensuring the IDE + remains responsive. + +### How to Use -This documentation provides an overview of the `DictationAction` class, its purpose, and the responsibilities of its methods and inner classes. It also includes brief descriptions of the properties and parameters used in the class. +1. **Start Dictation**: Trigger the VoiceToTextAction from the IDE's action menu. A status dialog appears indicating that + dictation is active. +2. **Dictate Your Code or Comments**: Speak clearly into your microphone. Your voice is captured, processed, and + transcribed into text in real-time. +3. **Stop Dictation**: Close the status dialog window to stop the dictation process. The transcription stops, and any + remaining audio is processed and inserted into the editor. + +### Requirements + +- A microphone connected to your computer. +- The VoiceToTextAction plugin installed in your IDE. + +### Troubleshooting + +- **Dictation Not Starting**: Ensure your microphone is properly connected and recognized by your system. +- **Poor Transcription Quality**: Speak clearly and at a moderate pace. Background noise can affect transcription + accuracy. +- **IDE Becomes Unresponsive**: Although designed to run in the background, extremely long dictation sessions may impact + IDE performance. Consider dictating in shorter bursts. + +### Support + +For issues, suggestions, or contributions, please visit the VoiceToTextAction plugin repository on GitHub. + +--- + +This documentation provides a concise overview of the VoiceToTextAction plugin's functionality and usage. For more +detailed information or to contribute to the project, please refer to the project's GitHub page. # generic\DiffChatAction.kt -Sure, here's the documentation for the `DiffChatAction` class: +## DiffChatAction Documentation -```kotlin -/** - * An action that opens a chat interface for generating code diffs based on the selected code or the entire file. - * - * When triggered, this action creates a new session and opens a web interface where the user can interact with - * an AI model to generate code diffs. The generated diffs are rendered with links that allow the user to apply - * the changes directly to the code editor. - * - * The action supports the following features: - * - * - If text is selected in the code editor, the selected text is used as the input code. Otherwise, the entire - * file content is used. - * - The AI model is instructed to provide code patches in the diff format, using `+` for line additions and `-` - * for line deletions, with sufficient context before each change. - * - The generated response is rendered as HTML with Markdown support, and the diff sections are enhanced with - * links that allow the user to apply the changes to the code editor with a single click. - * - The web interface is opened in the default system browser, and the session is managed by a `CodeChatSocketManager` - * instance. - * - The action is enabled for all events. - * - * @property path The path at which the chat server is mounted. - * @property agents A map of active sessions and their corresponding `SocketManager` instances. - * @property root The root directory for storing data related to the code chat feature. - */ -class DiffChatAction : BaseAction() { - // ... -} -``` +### Overview + +The `DiffChatAction` class is part of a plugin designed to enhance coding productivity by integrating a chat-based +interface for generating and applying code diffs directly within the IDE. This action allows users to select a portion +of code, initiate a chat session, and receive suggestions in the form of diffs. These diffs can then be applied directly +to the code with ease. + +### Features + +- **Code Selection**: Users can select a specific portion of code or use the entire document for the chat session. +- **Chat Session Initiation**: A unique session is created for each chat, allowing for focused and relevant suggestions. +- **Diff Suggestions**: The chat interface provides code modifications in the diff format, making it clear what changes + are suggested. +- **Direct Application of Diffs**: Users can apply suggested diffs directly from the chat interface, streamlining the + code improvement process. +- **Markdown Rendering**: The chat interface renders responses in HTML, providing a rich and user-friendly experience. + +### Usage + +1. **Select Code**: Highlight the code segment you wish to discuss or leave unselected for the entire document. +2. **Activate DiffChatAction**: Trigger the `DiffChatAction` from the IDE's action menu. +3. **Chat Session**: A chat session will open in your default web browser, connected to the selected code segment. +4. **Receive and Apply Diffs**: Engage with the chat to receive diff suggestions. Use provided links to apply diffs + directly to your code. + +### Requirements + +- **IDE Support**: This action is designed for use within an IDE that supports the plugin, such as IntelliJ IDEA. +- **Desktop Environment**: A desktop environment capable of opening web links in a browser. + +### Limitations + +- **Selection Requirement**: For the action to initiate, a text selection or an open document must be present. +- **Browser Dependency**: The action requires a web browser to open the chat interface. + +### Troubleshooting + +- **Browser Not Opening**: Ensure your default web browser is set correctly and is capable of opening new tabs or + windows from external applications. +- **Diff Application Issues**: If diffs are not applying correctly, check for any conflicts or syntax errors in the + suggested changes. + +### Conclusion + +The `DiffChatAction` enhances coding efficiency by integrating a smart, chat-based diff suggestion and application +mechanism directly within the IDE. By streamlining the process of reviewing and applying code changes, it offers a novel +approach to code improvement and collaboration. + +# generic\MultiDiffChatAction.kt + +## MultiDiffChatAction Documentation + +### Overview + +The `MultiDiffChatAction` class is part of a larger system designed to facilitate coding assistance through a chat +interface. This action allows users to interact with an AI model that provides coding help in the form of code diffs. +Users can submit multiple files, and the AI will generate responses that include code modifications, explanations, and +suggestions. + +### Key Features + +- **Multi-File Support**: Users can submit multiple code files in different programming languages. The action processes + these files and prepares them for analysis by the AI model. +- **Dynamic Code Analysis**: The AI model analyzes the submitted code and generates responses that may include code + modifications, suggestions, and explanations. +- **Interactive Chat Interface**: Users interact with the AI through a chat interface, making it easier to ask questions + and receive assistance. +- **Real-Time Code Updates**: The action supports applying suggested code changes directly to the source files, allowing + users to quickly adopt the AI's recommendations. + +### How It Works + +1. **File Submission**: Users submit one or more code files through the interface. The action identifies the programming + language of each file based on its extension and prepares the content for analysis. + +2. **AI Interaction**: The submitted code is sent to an AI model designed to assist with coding tasks. The model + generates responses based on the code analysis, which may include code diffs, explanations, and suggestions. + +3. **Response Rendering**: The AI's responses are rendered in a chat interface. Code diffs are presented in a way that + users can easily understand the suggested changes. The action also supports rendering the responses in Markdown + format for better readability. + +4. **Applying Changes**: Users have the option to apply the suggested code changes directly from the chat interface. The + action updates the source files with the new code, reflecting the AI's recommendations. + +### Usage + +To use the `MultiDiffChatAction`, follow these steps: -This class extends `BaseAction` and overrides the `handle` method to perform the action when triggered. The `handle` method performs the following steps: +1. **Initiate Action**: Trigger the action from within the supported environment (e.g., an IDE or a web interface). -1. Retrieves the current editor and the selected text or the entire file content. -2. Creates a new session and a `CodeChatSocketManager` instance with the selected code, language, and other settings. -3. Customizes the `systemPrompt` and `renderResponse` methods of the `CodeChatSocketManager` to provide instructions for generating diffs and rendering the response with diff links. -4. Initializes a chat server application and associates the session with the `CodeChatSocketManager` instance. -5. Opens the chat interface in the default system browser. +2. **Submit Files**: Select and submit the code files you want assistance with. You can submit files in different + programming languages. -The `isEnabled` method always returns `true`, allowing the action to be enabled in all contexts. +3. **Interact with AI**: Use the chat interface to ask questions or request assistance. The AI will analyze your code + and provide responses. -The companion object contains utility methods for managing the chat server and sessions, as well as a logger instance. +4. **Apply Suggestions**: Review the AI's suggestions and apply any desired code changes directly through the interface. + +### Requirements + +- Compatible IDE or web interface for initiating the action. +- Internet connection for interacting with the AI model and applying code changes. + +### Conclusion + +The `MultiDiffChatAction` offers a novel way to receive coding assistance through an interactive chat interface. By +leveraging AI models to analyze code and generate suggestions, users can improve their code quality and efficiency. This +documentation provides a basic understanding of how to use the action and benefit from its features. # generic\LineFilterChatAction.kt -Sure, here's the documentation for the `LineFilterChatAction` class: +## LineFilterChatAction Documentation -```kotlin -/** - * This class represents an action that opens a chat interface for discussing and annotating code. - * When the action is triggered, it creates a new chat session with a prompt that includes the - * selected code or the entire file content if no selection is made. The chat interface allows - * the user to interact with an AI assistant to ask questions and receive explanations about the code. - * - * The chat interface is rendered in a web browser, and the responses from the AI assistant are - * formatted using Markdown. Additionally, the assistant can reference specific lines of code by - * including the line number in the response. - */ -class LineFilterChatAction : BaseAction() { - - /** - * The path where the chat application is hosted. - */ - val path = "/codeChat" - - /** - * Handles the action event and opens the chat interface. - * - * @param e The action event. - */ - override fun handle(e: AnActionEvent) { - // ... (implementation details) - } - - /** - * Checks if the action is enabled for the given event. - * - * @param event The action event. - * @return `true` if the action is enabled, `false` otherwise. - */ - override fun isEnabled(event: AnActionEvent) = true - - companion object { - // ... (companion object implementation details) - } -} -``` +### Overview + +The `LineFilterChatAction` class is part of a plugin designed to enhance coding productivity by providing an interactive +chat interface. This interface allows users to ask questions and receive assistance with their code directly within +their IDE. The action integrates with a chat model to analyze and respond to queries based on the selected or entire +code in the current editor. + +### Features + +- **Code Contextual Chat**: Engage in a chat session where the AI understands the context of your code, including + language and content. +- **Markdown Support**: Responses from the AI can include markdown formatting for better readability and structure. +- **Line Reference**: The AI can reference specific lines in its responses, making it easier to understand suggestions + or corrections. + +### How It Works + +1. **Activation**: The action is triggered within the IDE. It requires an active editor window with code. +2. **Session Creation**: A unique chat session is created for the interaction. +3. **Code Analysis**: The action extracts the code from the current editor, either the selected text or the entire + document if no text is selected. +4. **Chat Interface**: The user is directed to a web-based chat interface where they can ask questions and receive + responses related to the code. +5. **Interactive Responses**: The AI model provides responses, potentially including markdown and references to specific + lines in the code. + +### Requirements -The `LineFilterChatAction` class extends the `BaseAction` class and overrides the `handle` method to handle the action event. When the action is triggered, it retrieves the selected code or the entire file content, creates a new chat session with a prompt that includes the code, and opens the chat interface in a web browser. +- An active editor window in the IDE with the code you want to discuss. +- Desktop environment capable of opening web browsers for the chat interface. -The chat interface is powered by a `ChatSocketManager` instance, which is responsible for managing the chat session and rendering the responses from the AI assistant. The responses are formatted using Markdown, and the assistant can reference specific lines of code by including the line number in the response. +### Usage -The `isEnabled` method is overridden to always return `true`, indicating that the action is always enabled. +1. **Select Code** (Optional): Select a specific portion of code in the editor if you want to focus the chat on that + segment. +2. **Trigger Action**: Use the designated shortcut or menu option to activate the `LineFilterChatAction`. +3. **Chat Session**: A browser window/tab will open, directing you to the chat interface. Wait a moment if it doesn't + open immediately. +4. **Ask Questions**: Start asking your questions or discussing your code with the AI in the chat interface. +5. **Review Responses**: The AI's responses may include markdown formatting and line references for clarity. -The companion object contains utility methods and properties related to the chat application, such as initializing the application server, managing the chat sessions, and handling the application root directory. +### Troubleshooting + +- **Browser Not Opening**: Ensure your desktop environment supports opening web links and that no software is blocking + the action. +- **No Response in Chat**: Verify your internet connection and ensure the server hosting the chat model is operational. + +### Conclusion + +The `LineFilterChatAction` enhances coding efficiency by providing an AI-powered chat interface for real-time code +assistance. It leverages the context of your code, including language and structure, to offer relevant and interactive +support. + +# generic\GenerateDocumentationAction.kt + +## Documentation Compiler Action + +The Documentation Compiler Action is a feature designed for IntelliJ-based IDEs that assists developers in automatically +generating documentation for their projects. This action compiles documentation from selected files within a project, +leveraging natural language processing to enhance the documentation process. + +### Features + +- **Automatic Documentation Generation**: Automatically compiles documentation from selected project files. +- **Customizable Output**: Users can specify the output filename and the transformation message to tailor the + documentation process. +- **File Selection**: Allows users to select specific files for documentation compilation. +- **Concurrency Support**: Utilizes multi-threading to speed up the documentation compilation process. + +### How to Use + +1. **Select Files**: Right-click on a folder or a selection of files in your project that you wish to document. +2. **Configure Settings**: Upon triggering the action, a settings dialog will appear. Here, you can configure: + - **Transformation Message**: A custom message to guide the documentation transformation process. + - **Output Filename**: The name of the file where the compiled documentation will be saved. + - **Files to Process**: Select or deselect files to include in the documentation compilation. +3. **Compile Documentation**: After configuring the settings, proceed to compile the documentation. The action will + process the selected files, applying natural language processing to generate or enhance the documentation content. + +### Implementation Details + +- **File Selection Validation**: The action is only enabled for directories, ensuring that documentation is compiled at + a folder level. +- **Concurrency**: Utilizes a fixed thread pool to process multiple files concurrently, enhancing performance. +- **Dynamic Output File Naming**: If the specified output file already exists, the action automatically generates a new + filename to prevent overwriting. +- **IDE Integration**: Seamlessly integrates with the IDE's file system and editor, automatically opening the generated + documentation upon completion. + +### Requirements + +- IntelliJ-based IDE (e.g., IntelliJ IDEA, PyCharm) +- Java Development Kit (JDK) + +### Installation + +This action is part of a plugin package. To install: + +1. Open your IDE and navigate to the plugin marketplace. +2. Search for the plugin package containing `GenerateDocumentationAction`. +3. Install the plugin and restart your IDE. + +### Conclusion + +The Documentation Compiler Action streamlines the process of generating project documentation, making it easier for +developers to maintain up-to-date documentation for their projects. By automating the documentation process and +integrating directly with the IDE, this action saves time and enhances the quality of project documentation. # generic\RedoLast.kt -Sure, here's the documentation for the `RedoLast` action: +## RedoLast Action for IntelliJ -```kotlin -/** - * The RedoLast action is an IntelliJ action that allows users to redo the last AI Coder action they performed in the editor. - * - * This action is part of the AI Coder plugin for IntelliJ IDEA. It provides a convenient way for users to redo the last - * action performed by the AI Coder plugin in the current editor. - * - * To use this action, open the editor and select the RedoLast action from the editor context menu or use the corresponding - * keyboard shortcut (if configured). This will redo the last action that was performed in the editor by the AI Coder plugin. - * - * The action is enabled only if there is a previous AI Coder action that can be redone in the current editor. - * - * @see BaseAction The base class for IntelliJ actions in the AI Coder plugin. - * @see retry A utility function that manages the redo/undo operations for AI Coder actions. - */ -class RedoLast : BaseAction() { - - /** - * Handles the action event by redoing the last AI Coder action in the current editor. - * - * @param e The action event containing information about the context in which the action was invoked. - */ - override fun handle(e: AnActionEvent) { - retry[e.getRequiredData(CommonDataKeys.EDITOR).document]!!.run() - } - - /** - * Checks if the action is enabled in the current context. - * - * The action is enabled if there is a previous AI Coder action that can be redone in the current editor. - * - * @param event The action event containing information about the context in which the action was invoked. - * @return `true` if the action is enabled, `false` otherwise. - */ - override fun isEnabled(event: AnActionEvent): Boolean { - return null != retry[event.getRequiredData(CommonDataKeys.EDITOR).document] - } -} -``` +### Overview -This documentation explains the purpose of the `RedoLast` action, how to use it, and the conditions under which it is enabled. It also provides brief descriptions of the `handle` and `isEnabled` functions, explaining their roles and parameters. +The RedoLast action is a feature designed for IntelliJ users who are utilizing AI Coder. It enables users to easily redo +the last AI Coder action they executed within the editor. This functionality is particularly useful for quickly +reverting and reapplying changes made by AI Coder, enhancing productivity and workflow efficiency. -# generic\MultiDiffChatAction.kt +### How to Use -Sure, here's the documentation for the `MultiDiffChatAction` class: +To utilize the RedoLast action, follow these simple steps: -```kotlin -/** - * The MultiDiffChatAction class is an action that allows users to interact with an AI assistant - * to modify multiple code files simultaneously. When the action is triggered, it opens a web-based - * chat interface where the user can ask questions and provide instructions to the AI assistant. - * The assistant can then suggest code changes in the form of diffs, which can be applied to the - * selected files with a single click. - * - * The action works as follows: - * - * 1. The user selects one or more files in the IDE. - * 2. The action retrieves the contents of the selected files and their associated programming languages. - * 3. A chat session is created with a custom prompt that includes the contents of the selected files. - * 4. The chat interface is opened in the user's default web browser. - * 5. The user can interact with the AI assistant through the chat interface. - * 6. When the assistant suggests code changes in the form of diffs, the user can apply these changes - * to the corresponding files with a single click. - * - * The action uses the following components: - * - * - `ChatSocketManager`: Manages the chat session and handles user input and AI responses. - * - `ApplicationServer`: Provides the web-based chat interface. - * - `StorageInterface`: Manages the storage of chat sessions and associated data. - * - * The `handle` function is the entry point of the action. It retrieves the selected files, creates - * the chat session, and opens the chat interface in the user's web browser. - * - * The `commonRoot` extension function is used to find the common root directory of the selected files. - * This is used to display relative file paths in the chat interface. - * - * The `commonPrefixWith` extension function is a helper function used by `commonRoot`. - */ -class MultiDiffChatAction : BaseAction() { - // Implementation details... -} -``` +1. **Open the Editor**: Ensure you are in the IntelliJ editor where you previously performed an AI Coder action. +2. **Access the Context Menu**: Right-click within the editor to open the context menu. +3. **Select RedoLast**: Look for the RedoLast action in the context menu and select it. -This documentation explains the purpose of the `MultiDiffChatAction` class, its workflow, the components it uses, and the roles of the `handle`, `commonRoot`, and `commonPrefixWith` functions. It should provide a clear understanding of how the action works and what it does. +Upon selection, the RedoLast action will automatically redo the last AI Coder action that was performed in the editor. -# generic\DocumentationCompilerAction.kt +### Availability -Sure, here's the documentation for the `DocumentationCompilerAction` class: +The RedoLast action is available only when there is a previous AI Coder action to redo. If no such action exists, the +RedoLast option will be disabled. -```kotlin -/** - * An action that allows the user to select files and provide instructions to generate documentation - * using an AI model. The generated documentation is saved to a file in the selected directory. - */ -class DocumentationCompilerAction : FileContextAction() { - - /** - * Checks if the action is enabled for the given event. The action is enabled only if a non-directory - * file is selected. - * - * @param event The action event. - * @return True if the action is enabled, false otherwise. - */ - override fun isEnabled(event: AnActionEvent): Boolean { - if (UITools.getSelectedFile(event)?.isDirectory == false) return false - return super.isEnabled(event) - } - - /** - * A class to hold the settings for the action. - * - * @property settings The user-defined settings, or null if not set. - * @property project The current project, or null if not available. - */ - class Settings( - val settings: UserSettings? = null, - val project: Project? = null - ) - - /** - * A class to hold the user-defined settings for the action. - * - * @property transformationMessage The instruction message for the AI model. - * @property outputFilename The name of the output file for the generated documentation. - * @property filesToProcess The list of files to process for documentation generation. - */ - class UserSettings( - var transformationMessage: String = "Create user documentation", - var outputFilename: String = "compiled_documentation.md", - var filesToProcess: List = listOf(), - ) - - /** - * A class to hold the UI elements for the settings dialog. - */ - class SettingsUI { - @Name("Files to Process") - val filesToProcess = CheckBoxList() - - @Name("AI Instruction") - val transformationMessage = JBTextField() - - @Name("Output File") - val outputFilename = JBTextField() - } - - /** - * Gets the configuration for the action by displaying a settings dialog to the user. - * - * @param project The current project, or null if not available. - * @param e The action event. - * @return The settings for the action. - */ - override fun getConfig(project: Project?, e: AnActionEvent): Settings { ... } - - /** - * Processes the selected files and generates documentation using the provided configuration. - * - * @param state The selection state containing the selected file. - * @param config The configuration for the action. - * @return An array of generated files. - */ - override fun processSelection(state: SelectionState, config: Settings?): Array { ... } - - /** - * Transforms the given file content using the provided transformation message and an AI model. - * - * @param fileContent The content of the file to transform. - * @param transformationMessage The instruction message for the AI model. - * @return The transformed content. - */ - private fun transformContent(fileContent: String, transformationMessage: String): String { ... } - - companion object { - /** - * Opens the generated documentation file in the IDE. - * - * @param project The current project. - * @param outputPath The path of the generated documentation file. - */ - fun open(project: Project, outputPath: Path) { ... } - } - - /** - * A dialog for configuring the settings for the documentation compiler action. - * - * @property project The current project, or null if not available. - * @property settingsUI The UI elements for the settings dialog. - */ - class DocumentationCompilerDialog(project: Project?, private val settingsUI: SettingsUI) : DialogWrapper(project) { - val userSettings = UserSettings() - - init { ... } - - override fun createCenterPanel(): JComponent? { ... } - - override fun doOKAction() { ... } - } -} +### Key Features -/** - * An extension property to get the list of items in a CheckBoxList. - */ -private val CheckBoxList.items: List - get() { ... } -``` +- **Ease of Use**: Quickly redo the last AI Coder action with a simple selection from the context menu. +- **Efficiency**: Saves time by allowing users to easily revert and reapply changes. +- **Integration**: Seamlessly works within the IntelliJ environment, enhancing the AI Coder experience. -This class provides an action that allows the user to select files and provide instructions for generating documentation using an AI model. The generated documentation is saved to a file in the selected directory. +### Requirements -The `DocumentationCompilerAction` class extends `FileContextAction` and overrides the `isEnabled` method to check if the action is enabled for the given event. The action is enabled only if a non-directory file is selected. +To use the RedoLast action, you must have: -The `Settings` class holds the user-defined settings and the current project. The `UserSettings` class holds the user-defined settings for the action, including the instruction message for the AI model, the name of the output file, and the list of files to process. +- IntelliJ IDE installed. +- AI Coder plugin enabled in your IntelliJ environment. -The `SettingsUI` class holds the UI elements for the settings dialog, including a `CheckBoxList` for selecting files, text fields for the instruction message and output file name. +### Conclusion -The `getConfig` method displays a settings dialog to the user and returns the configuration for the action. The `processSelection` method processes the selected files and generates documentation using the provided configuration. The `transformContent` method transforms the given file content using the provided transformation message and an AI model. +The RedoLast action is a valuable tool for developers using AI Coder in IntelliJ, offering a quick and efficient way to +redo actions. By integrating this feature into your workflow, you can enhance your productivity and streamline your +development process. -The `open` function in the companion object opens the generated documentation file in the IDE. +# generic\ReplaceWithSuggestionsAction.kt -The `DocumentationCompilerDialog` class is a dialog for configuring the settings for the documentation compiler action. It extends `DialogWrapper` and provides a custom UI for the settings. +## ReplaceWithSuggestionsAction Documentation -Finally, the `items` extension property provides a convenient way to get the list of items in a `CheckBoxList`. +### Overview -# generic\ReplaceOptionsAction.kt +`ReplaceWithSuggestionsAction` is an IntelliJ IDEA plugin action designed to assist developers by suggesting alternative text +options for a selected piece of code or text within the IDE. This action leverages a virtual API to generate suggestions +based on the context surrounding the selected text, aiming to enhance code quality and developer productivity. -Sure, here's the documentation for the `ReplaceOptionsAction` class: +### Key Features -```kotlin -/** - * An action that suggests replacement options for the selected text based on the surrounding context. - * - * This action uses a virtual API to generate suggestions for replacing the selected text with a new - * text that fits the context. The virtual API is implemented using a ChatProxy, which sends a - * request to a language model with the selected text and its surrounding context as examples. - * - * The action presents the user with a dialog to choose from the suggested options. The chosen option - * replaces the selected text in the editor. - */ -open class ReplaceOptionsAction : SelectionAction() { - - /** - * A virtual API interface for suggesting text based on a template and examples. - */ - interface VirtualAPI { - /** - * Suggests text to fill in the blank in the given template based on the provided examples. - * - * @param template A string with a blank (`_____`) to be filled in. - * @param examples A list of example strings to guide the suggestions. - * @return A Suggestions object containing a list of suggested choices. - */ - fun suggestText(template: String, examples: List): Suggestions - - /** - * A data class to hold the suggested choices. - */ - class Suggestions { - /** - * A list of suggested choices for filling in the blank. - */ - var choices: List? = null - } - } - - /** - * A proxy to the virtual API implemented using a ChatProxy. - */ - val proxy: VirtualAPI - get() = ChatProxy( - clazz = VirtualAPI::class.java, - api = api, - model = AppSettingsState.instance.defaultChatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ).create() - - /** - * Returns an empty string as the configuration for this action. - */ - override fun getConfig(project: Project?): String = "" - - /** - * Processes the selected text and generates replacement options using the virtual API. - * - * @param event The action event that triggered this action. - * @param state The selection state containing the selected text and its context. - * @param config The configuration for this action (not used). - * @return The chosen replacement option for the selected text. - */ - override fun processSelection(event: AnActionEvent?, state: SelectionState, config: String?): String { - val choices = UITools.run(event?.project, templateText, true, true) { - val selectedText = state.selectedText - val idealLength = 2.0.pow(2 + ceil(ln(selectedText?.length?.toDouble() ?: 1.0))).toInt() - val selectionStart = state.selectionOffset - val allBefore = state.entireDocument?.substring(0, selectionStart) ?: "" - val selectionEnd = state.selectionOffset + (state.selectionLength ?: 0) - val allAfter = state.entireDocument?.substring(selectionEnd, state.entireDocument.length) ?: "" - val before = StringUtil.getSuffixForContext(allBefore, idealLength).toString().replace('\n', ' ') - val after = StringUtil.getPrefixForContext(allAfter, idealLength).toString().replace('\n', ' ') - proxy.suggestText( - "$before _____ $after", - listOf(selectedText.toString()) - ).choices - } - return choose(choices ?: listOf()) - } - - /** - * Presents a dialog to the user to choose from the given list of options. - * - * @param choices A list of options to choose from. - * @return The chosen option, or an empty string if no option was chosen. - */ - open fun choose(choices: List): String = - UITools.showRadioButtonDialog("Select an option to fill in the blank:", *choices.toTypedArray())?.toString() ?: "" -} -``` +- **Context-Aware Suggestions:** Generates text suggestions based on the content before and after the selected text, + ensuring relevance. +- **Customizable Suggestions:** Utilizes a virtual API, allowing for customization of the suggestion engine. +- **User-Friendly Interface:** Offers a simple dialog with radio buttons for users to choose from the generated + suggestions. -This class extends the `SelectionAction` class and overrides the `processSelection` method to generate replacement options for the selected text using a virtual API implemented with a `ChatProxy`. The `choose` method presents a dialog to the user to select one of the suggested options. +### How It Works -The `VirtualAPI` interface defines a `suggestText` method that takes a template string with a blank (`_____`) and a list of examples, and returns a `Suggestions` object containing a list of suggested choices for filling in the blank. +1. **Selection:** The user selects a piece of text within their code. +2. **Context Analysis:** The plugin calculates an ideal length for context analysis and extracts the text before and + after the selection. +3. **Suggestion Generation:** The virtual API is called with the contextual information to generate a list of + suggestions. +4. **User Selection:** A dialog is presented to the user, allowing them to choose one of the suggested options to + replace the selected text. -The `proxy` property creates an instance of the `VirtualAPI` using the `ChatProxy` class, which sends a request to a language model with the selected text and its surrounding context as examples. +### Components -In the `processSelection` method, the selected text and its surrounding context are extracted from the `SelectionState` object. The context is truncated to an ideal length based on the length of the selected text. The `suggestText` method of the `proxy` is then called with the context and the selected text as an example, and the resulting list of suggested choices is returned. +#### VirtualAPI Interface -The `choose` method displays a dialog with the suggested choices as radio buttons, allowing the user to select one of the options. The chosen option is returned as the result of the `processSelection` method. +Defines the contract for the suggestion engine, including the `suggestText` method which takes a template string and a +list of examples to generate suggestions. -# generic\WebDevAction.kt +##### Suggestions Class -Sure, here's the documentation for the `WebDevAction` class: +A nested class within `VirtualAPI` that holds the generated suggestions. -```kotlin -/** - * This class represents an action in the IntelliJ IDEA plugin that provides a web development assistant. - * When triggered, it opens a new browser window with a web application that allows the user to describe - * their desired web application, and the assistant will generate the necessary code files (HTML, CSS, JavaScript, etc.) - * based on the user's input. - * - * The action is enabled only when a folder is selected in the project view. - * - * The main components of this class are: - * - * 1. [WebDevAction]: The main action class that handles the user's action and initializes the web application. - * 2. [WebDevApp]: The web application server that handles user input and generates code files. - * 3. [WebDevAgent]: The agent system that manages different actors responsible for generating code for different file types. - * - * The [WebDevApp] class uses an [ActorSystem] to manage different actors responsible for generating code for different file types. - * The actors are defined in the [WebDevAgent] class, and they include: - * - * - [HtmlCodingActor]: Generates HTML code based on the user's input. - * - [JavascriptCodingActor]: Generates JavaScript code based on the user's input. - * - [CssCodingActor]: Generates CSS code based on the user's input. - * - [ArchitectureDiscussionActor]: Generates a detailed architecture for the web application based on the user's input. - * - [CodeReviewer]: Analyzes the generated code, looks for bugs, and provides fixes. - * - [EtcCodingActor]: Generates other types of files (e.g., JSON, XML) based on the user's input. - * - * The [WebDevAgent] class orchestrates the interaction between these actors to generate the complete web application code. - * It also provides a user interface for the user to provide feedback and revise the generated code. - * - * Overall, this action provides a convenient way for developers to quickly generate web application code based on natural language input, - * leveraging the power of language models and the IntelliJ IDEA plugin ecosystem. - */ -class WebDevAction : BaseAction() { - // ... -} -``` +#### Proxy -This documentation explains the purpose of the `WebDevAction` class, its main components, and the roles of the different actors involved in generating the web application code. It also provides an overview of how the different components interact with each other to achieve the desired functionality. +A property that initializes the virtual API proxy with configuration settings from `AppSettingsState`, such as the model +and temperature for generating suggestions. -# generic\TaskRunnerAction.kt +### Usage -The provided Kotlin code is an IntelliJ plugin action that integrates with a web UI and utilizes AI models to assist in task planning, documentation generation, new file creation, file patching, and inquiries. Here's a breakdown of the key components and their functionalities: +- **Initialization:** The action is initialized within the IntelliJ IDEA environment and listens for user selection. +- **Selection:** The user highlights the text they wish to replace. +- **Execution:** The action is triggered, either via a menu option or a shortcut, initiating the suggestion generation + process. +- **Choice:** The user is presented with a dialog to choose one of the generated suggestions. +- **Replacement:** The selected suggestion replaces the original text. -1. **TaskRunnerAction** - - This class extends `BaseAction` and is responsible for initiating the task planning process. - - When the action is triggered, it creates a new session, selects the current file or folder, and initializes the `TaskRunnerApp`. - - It also opens a browser window with the application server URL. +### Configuration -2. **TaskRunnerApp** - - This class extends `ApplicationServer` and serves as the main application server for the task planning process. - - It handles user messages by creating a `TaskRunnerAgent` instance and starting the task processing. - - It also manages sessions and settings for the application. +The action utilizes settings from `AppSettingsState` for configuring the virtual API, including: -3. **TaskRunnerAgent** - - This class extends `ActorSystem` and is responsible for processing user messages and delegating tasks to specific actors based on the task type. - - It defines several actors for different tasks, such as `TaskBreakdownActor`, `DocumentationGeneratorActor`, `NewFileCreatorActor`, `FilePatcherActor`, and `InquiryActor`. - - The `startProcess` method is the entry point for processing user messages. It breaks down the user request into smaller tasks using the `TaskBreakdownActor`, and then executes each task concurrently using a thread pool. - - The `runTask` method handles the execution of individual tasks based on their type (e.g., creating new files, editing existing files, generating documentation, answering inquiries, or performing task planning). +- The default chat model. +- The temperature setting for suggestion variability. -4. **Actors** - - The actors are responsible for performing specific tasks based on the user request and the provided context. - - The `TaskBreakdownActor` identifies and lists smaller, actionable tasks from the user request. - - The `DocumentationGeneratorActor` generates documentation for the provided code. - - The `NewFileCreatorActor` creates new files based on the given requirements. - - The `FilePatcherActor` generates patches for existing files to modify their functionality or fix issues. - - The `InquiryActor` provides responses to user inquiries by compiling relevant information and insights. +### Extensibility -5. **Task Breakdown and Execution** - - The `TaskBreakdownResult` data class represents the output of the `TaskBreakdownActor`, containing a map of tasks and a final task ID. - - The `Task` data class represents an individual task, including its description, type, dependencies, input files, and output files. - - The `TaskType` enum defines the different types of tasks (TaskPlanning, Inquiry, NewFile, EditFile, Documentation). - - The `GenState` data class keeps track of the subtasks, task IDs, reply text, completed tasks, and task futures during the execution process. - - The `executionOrder` function determines the order in which tasks should be executed based on their dependencies. - - The `buildMermaidGraph` function generates a Mermaid graph representation of the task dependencies. +Developers can extend `ReplaceWithSuggestionsAction` to customize the suggestion process or the user interface for selecting +suggestions. The `choose` method can be overridden to implement different mechanisms for presenting and selecting among +the suggestions. -The code provides a comprehensive system for task planning, code generation, documentation, and inquiries, leveraging AI models and a web UI for user interaction. It demonstrates a modular design with separate actors for different tasks, allowing for easy extensibility and maintenance. +### Conclusion + +`ReplaceWithSuggestionsAction` is a powerful tool for IntelliJ IDEA users, offering smart, context-aware suggestions to improve +code quality and accelerate development workflows. Through its integration with a virtual API, it provides a flexible +and customizable solution for code enhancement. # markdown\MarkdownImplementActionGroup.kt -Sure, here's the documentation for the provided code: +## Markdown Implement Action Group Documentation -```kotlin -package com.github.simiacryptus.aicoder.actions.markdown - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionGroup -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.proxy.ChatProxy - -/** - * An ActionGroup that provides actions to implement the selected text in various programming languages using Markdown. - */ -class MarkdownImplementActionGroup : ActionGroup() { - private val markdownLanguages = listOf( - "sql", "java", "asp", "c", "clojure", "coffee", "cpp", "csharp", "css", "bash", "go", "java", "javascript", - "less", "make", "matlab", "objectivec", "pascal", "PHP", "Perl", "python", "rust", "scss", "sql", "svg", - "swift", "ruby", "smalltalk", "vhdl" - ) - - override fun update(e: AnActionEvent) { - e.presentation.isEnabledAndVisible = isEnabled(e) - super.update(e) - } - - companion object { - /** - * Checks if the action should be enabled for the given event. - * @param e The action event. - * @return True if the action should be enabled, false otherwise. - */ - fun isEnabled(e: AnActionEvent): Boolean { - val computerLanguage = ComputerLanguage.getComputerLanguage(e) ?: return false - if (ComputerLanguage.Markdown != computerLanguage) return false - return UITools.hasSelection(e) - } - } - - override fun getChildren(e: AnActionEvent?): Array { - if (e == null) return emptyArray() - val computerLanguage = ComputerLanguage.getComputerLanguage(e) ?: return emptyArray() - val actions = markdownLanguages.map { language -> MarkdownImplementAction(language) } - return actions.toTypedArray() - } - - /** - * An action that implements the selected text in a specific programming language using Markdown. - */ - open class MarkdownImplementAction(private val language: String) : SelectionAction(true) { - init { - templatePresentation.text = language - templatePresentation.description = language - } - - /** - * An interface for the conversion API. - */ - interface ConversionAPI { - /** - * Implements the given text in the specified computer language. - * @param text The text to implement. - * @param humanLanguage The human language of the input text. - * @param computerLanguage The computer language to implement the text in. - * @return The converted text. - */ - fun implement(text: String, humanLanguage: String, computerLanguage: String): ConvertedText - - /** - * A data class representing the converted text. - */ - class ConvertedText { - var code: String? = null - var language: String? = null - } - } - - /** - * Gets the proxy for the conversion API. - * @return The conversion API proxy. - */ - private fun getProxy(): ConversionAPI { - return ChatProxy( - clazz = ConversionAPI::class.java, - api = api, - model = AppSettingsState.instance.defaultChatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ).create() - } - - override fun getConfig(project: Project?): String { - return "" - } - - /** - * Processes the selected text and implements it in the specified programming language using Markdown. - * @param state The selection state. - * @param config The configuration (not used in this implementation). - * @return The Markdown-formatted code block with the implemented code. - */ - override fun processSelection(state: SelectionState, config: String?): String { - val code = getProxy().implement(state.selectedText ?: "", "autodetect", language).code ?: "" - return """ - | - | - |```$language - |$code - |``` - | - |""".trimMargin() - } - } -} -``` +The `MarkdownImplementActionGroup` is an extension designed for IntelliJ-based IDEs that enhances your Markdown editing +capabilities by allowing you to automatically generate code snippets in various programming languages directly from your +Markdown files. This feature is particularly useful for developers, technical writers, and educators who frequently +create technical documentation or tutorials. -This code defines an `ActionGroup` called `MarkdownImplementActionGroup` that provides actions to implement the selected text in various programming languages using Markdown. The group contains a list of supported programming languages (`markdownLanguages`). +### Features -The `isEnabled` function checks if the action should be enabled for the given event. It checks if the current file is a Markdown file and if there is a text selection. +- **Multi-Language Support**: Supports a wide range of programming languages including SQL, Java, C, C++, Python, Ruby, + and many more, allowing you to generate code snippets in the language of your choice. +- **Automatic Code Generation**: Utilizes a conversion API to transform selected text into code snippets, making it + easier to include code examples in your Markdown files. +- **Easy Integration**: Seamlessly integrates with your development environment, providing a straightforward way to + enhance your Markdown documents without leaving your IDE. -The `getChildren` function creates an array of `MarkdownImplementAction` instances, one for each supported programming language. +### How It Works -The `MarkdownImplementAction` class is an implementation of the `SelectionAction` interface. It defines an interface called `ConversionAPI` that provides a method `implement` to convert the selected text into code in the specified programming language. +1. **Language Detection**: The action group first checks if the current file is a Markdown file and if there is a text + selection within it. +2. **Action Visibility**: If the conditions are met, the action becomes visible and enabled in the IDE's context menu. +3. **Code Generation**: Upon selection of the desired programming language from the context menu, the extension + communicates with a conversion API to generate a code snippet based on the selected text. +4. **Snippet Insertion**: The generated code snippet is then formatted and inserted into the Markdown document, wrapped + in the appropriate code block syntax for the selected language. -The `getProxy` function creates an instance of the `ConversionAPI` using the `ChatProxy` class from the `com.simiacryptus.jopenai.proxy` package. It configures the proxy with the API key, the default chat model, temperature, and the number of deserialization retries. +### Usage -The `processSelection` function is the main logic of the action. It calls the `implement` method of the `ConversionAPI` with the selected text, the human language ("autodetect"), and the target programming language. It then formats the resulting code as a Markdown code block and returns it. +To use the `MarkdownImplementActionGroup`, follow these steps: -Overall, this code provides a convenient way to implement selected text in various programming languages within a Markdown file using an AI-powered conversion API. +1. Open a Markdown file in your IntelliJ-based IDE. +2. Select the text you wish to convert into a code snippet. +3. Right-click to open the context menu and navigate to the `Markdown Implement Action Group` submenu. +4. Choose the programming language for your code snippet from the list. +5. The extension will automatically generate and insert the code snippet into your document. -# markdown\MarkdownListAction.kt +### Requirements -Sure, here's the documentation for the `MarkdownListAction` class: +- IntelliJ-based IDE (e.g., IntelliJ IDEA, PyCharm, WebStorm) +- Java Development Kit (JDK) -```kotlin -/** - * An action that generates new list items for a selected Markdown list in the editor. - * - * This action is enabled when the current file is a Markdown file and the caret or selection is inside a Markdown list. - * When triggered, it extracts the existing list items, sends them to an AI model, and generates new list items based on - * the existing ones. The new items are then appended to the end of the list in the editor. - * - * The AI model used for generating new list items is defined by the `ListAPI` interface, which is implemented using - * the OpenAI API via the `ChatProxy` class. The `ListAPI` interface has a single method `newListItems` that takes - * a list of existing items and a desired count, and returns a new list of items. - * - * The action also handles different bullet types (-, *, and numbered lists) and preserves the indentation of the - * original list. - */ -class MarkdownListAction : BaseAction() { - // ... -} -``` +### Installation -The `ListAPI` interface and its `Items` data class: +This extension can be installed from the JetBrains Marketplace or by downloading the plugin JAR file and installing it +manually through your IDE's plugin settings. -```kotlin -/** - * An interface defining the API for generating new list items. - */ -interface ListAPI { - /** - * Generates new list items based on the provided existing items and desired count. - * - * @param items The existing list items. - * @param count The desired total count of items (existing + new). - * @return A data class containing the new list items. - */ - fun newListItems( - items: List?, - count: Int, - ): Items - - /** - * A data class representing the result of the `newListItems` function. - * - * @property items The new list items. - */ - data class Items( - val items: List? = null, - ) -} -``` +### Conclusion -The `handle` function: +The `MarkdownImplementActionGroup` is a powerful tool for anyone involved in creating or editing Markdown documents that +include code snippets. By automating the code generation process, it not only saves time but also ensures consistency +and accuracy in your documentation. -```kotlin -/** - * The main function that handles the action when triggered. - * - * @param e The action event containing information about the current editor state. - */ -override fun handle(e: AnActionEvent) { - // ... -} -``` +# generic\WebDevelopmentAssistantAction.kt -The `isEnabled` function: +## Web Development Assistant Plugin Documentation -```kotlin -/** - * Checks if the action should be enabled based on the current editor state. - * - * @param event The action event containing information about the current editor state. - * @return `true` if the action should be enabled, `false` otherwise. - */ -override fun isEnabled(event: AnActionEvent): Boolean { - // ... -} -``` +### Overview -This documentation explains the purpose of the `MarkdownListAction` class, the `ListAPI` interface used for generating new list items, and the main functions `handle` and `isEnabled`. It also provides brief descriptions of the parameters and return values for the relevant functions. +The Web Development Assistant is an IntelliJ IDEA plugin designed to streamline the process of developing web +applications. It leverages AI to assist in generating code, reviewing code, and suggesting architectural designs for web +projects directly within the IDE environment. -# SelectionAction.kt +### Features -Sure, here's the documentation for the `SelectionAction` class: +- **Code Generation**: Automatically generates HTML, CSS, and JavaScript code based on user input. +- **Code Review**: Analyzes code for potential issues and suggests improvements or fixes. +- **Architecture Suggestion**: Provides detailed architecture suggestions for web applications, including + framework/library recommendations and CDN links. +- **Session Management**: Supports multiple development sessions with unique settings and resources. +- **Interactive Feedback**: Allows users to provide feedback on generated code and suggestions, facilitating iterative + improvement. -```kotlin -/** - * An abstract class that provides a base implementation for actions that operate on selected text - * or a default selection in an editor. This class handles the selection of text, retrieves the - * necessary context information, and delegates the actual processing of the selection to subclasses. - * - * @param T The type of the configuration object used by the action. - * @property requiresSelection Whether the action requires a non-empty selection to be enabled. - * If set to false, the action will use a default selection if no text - * is selected. - */ -abstract class SelectionAction( - private val requiresSelection: Boolean = true -) : BaseAction() { - - /** - * Returns the configuration object for the action, or null if no configuration is needed. - * - * @param project The current project, or null if no project is available. - * @return The configuration object, or null if no configuration is needed. - */ - open fun getConfig(project: Project?): T? = null - - // ... (implementation details omitted for brevity) ... - - /** - * Determines whether the action is enabled for the given event. - * - * @param event The action event. - * @return True if the action is enabled, false otherwise. - */ - override fun isEnabled(event: AnActionEvent): Boolean { /* ... */ } - - /** - * Data class representing the state of the selection and its context. - * - * @property selectedText The selected text, or null if no text is selected. - * @property selectionOffset The offset of the selection start. - * @property selectionLength The length of the selection, or null if no text is selected. - * @property entireDocument The entire document text, or null if not available. - * @property language The programming language of the document, or null if not available. - * @property indent The indentation string to use, or null if not available. - * @property contextRanges An array of context ranges surrounding the selection. - * @property psiFile The PSI file representing the document, or null if not available. - * @property project The current project, or null if no project is available. - */ - data class SelectionState( - val selectedText: String? = null, - val selectionOffset: Int = 0, - val selectionLength: Int? = null, - val entireDocument: String? = null, - val language: ComputerLanguage? = null, - val indent: CharSequence? = null, - val contextRanges: Array = arrayOf(), - val psiFile: PsiFile?, - val project: Project? - ) - - /** - * Determines whether the action supports the given programming language. - * - * @param computerLanguage The programming language. - * @return True if the language is supported, false otherwise. - */ - open fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { /* ... */ } - - /** - * Returns the default selection range for the given offset if no text is selected. - * - * @param editorState The state of the editor. - * @param offset The offset for which to get the default selection. - * @return A pair representing the start and end offsets of the default selection. - */ - open fun defaultSelection(editorState: EditorState, offset: Int): Pair { /* ... */ } - - /** - * Adjusts the given selection range if needed. - * - * @param state The state of the editor. - * @param start The start offset of the selection. - * @param end The end offset of the selection. - * @return A pair representing the adjusted start and end offsets of the selection. - */ - open fun editSelection(state: EditorState, start: Int, end: Int): Pair { /* ... */ } - - /** - * Processes the selected text or the default selection using the provided configuration. - * - * @param event The action event, or null if not available. - * @param selectionState The state of the selection and its context. - * @param config The configuration object for the action, or null if no configuration is needed. - * @return The processed text. - */ - open fun processSelection( - event: AnActionEvent?, - selectionState: SelectionState, - config: T? - ): String { /* ... */ } - - /** - * Processes the selected text or the default selection using the provided configuration. - * This method must be implemented by subclasses to perform the actual processing. - * - * @param state The state of the selection and its context. - * @param config The configuration object for the action, or null if no configuration is needed. - * @return The processed text. - */ - open fun processSelection(state: SelectionState, config: T?): String { - throw NotImplementedError() - } -} -``` +### Getting Started + +1. **Installation**: Ensure the plugin is installed in your IntelliJ IDEA environment. +2. **Accessing the Plugin**: Navigate to the plugin through IntelliJ IDEA's action or menu system. +3. **Starting a Session**: Initiate a new web development session by selecting a target folder for your project. +4. **Interacting with the Assistant**: Provide your requirements or queries to the assistant through the provided UI. + The assistant will generate code, review existing code, or suggest architectural designs based on your input. +5. **Reviewing Suggestions**: Examine the assistant's output, which may include code snippets, architectural designs, or + code review comments. +6. **Providing Feedback**: Use the interactive feedback system to refine the suggestions, asking for revisions or + clarifications as needed. + +### Key Components + +- **WebDevelopmentAssistantAction**: The main class that handles user actions, initiating sessions, and opening the browser interface for + interaction. +- **WebDevApp**: Represents a web development session, managing settings, user messages, and interactions with the AI. +- **WebDevAgent**: Acts as the intermediary between the user and the AI, handling specific tasks like code generation, + code review, and architecture suggestion. +- **Session Management**: Sessions are uniquely identified and managed, allowing for persistent settings and + interactions within a project. + +### Usage Tips + +- **Clear Requirements**: Provide clear and concise requirements to the assistant for more accurate suggestions. +- **Iterative Feedback**: Use the feedback loop effectively by reviewing suggestions and providing specific feedback for + improvements. +- **Explore Architectural Suggestions**: Take advantage of the architectural suggestions for insights on structuring + your web application and selecting appropriate technologies. + +### Troubleshooting + +- **Browser Issues**: If the browser does not open automatically, manually navigate to the provided URL. +- **Session Persistence**: Ensure your project folder is correctly selected to maintain session continuity. +- **Feedback Loop**: If feedback is not being correctly processed, ensure you are providing it in the expected format + and context. + +### Conclusion + +The Web Development Assistant plugin offers a powerful toolset for accelerating web development projects by integrating +AI-driven code generation, review, and architectural suggestions directly into the IntelliJ IDEA environment. By +following the guidelines and making effective use of the features, developers can enhance their productivity and focus +on creative aspects of web development. + +# markdown\MarkdownListAction.kt + +## Markdown List Action Documentation + +### Overview + +The `MarkdownListAction` class is designed to enhance your Markdown editing experience in IntelliJ-based IDEs by +automatically generating and inserting list items into your Markdown files. This action is particularly useful when +you're looking to quickly expand lists with new, contextually relevant items without manually brainstorming and typing +each one. + +### Features + +- **Automatic List Item Generation:** Leverages AI to generate new list items based on the existing ones in your + Markdown document. +- **Context-Aware:** Understands the context of your list to provide relevant suggestions. +- **Customizable Item Count:** Allows specifying the number of new items to generate. +- **Support for Different Bullet Types:** Works with various bullet types including `- [ ]` (task list), `-`, and `*`. + +### How It Works + +1. **Selection Identification:** The action identifies the list you're working on based on your text selection in a + Markdown file. +2. **Item Extraction:** It extracts existing list items and sends them to an AI service, which then generates additional + items based on the context. +3. **List Expansion:** The new items are inserted into your document, directly after the selected list, maintaining the + original list's formatting and bullet type. + +### Usage + +To use the `MarkdownListAction`, follow these steps: + +1. **Open a Markdown File:** Ensure you're working in a file recognized as Markdown by your IDE. +2. **Select a List:** Highlight a portion of the list you wish to expand. It's important that the selection includes + part of the list recognized by the IDE as `MarkdownListImpl`. +3. **Activate the Action:** Trigger the `MarkdownListAction`. This can be done through a menu option or a keyboard + shortcut, depending on how it's configured in your IDE. +4. **Wait for Generation:** The action communicates with an AI service to generate new items. Once the process is + complete, the new items are automatically inserted into your document. -This class provides a base implementation for actions that operate on selected text or a default selection in an editor. It handles the selection of text, retrieves the necessary context information (such as the programming language, indentation, and surrounding code elements), and delegates the actual processing of the selection to subclasses. +### Requirements -Subclasses can override the `processSelection` method to implement their specific logic for processing the selected text or the default selection. They can also provide a configuration object by overriding the `getConfig` method. +- IntelliJ-based IDE (e.g., IntelliJ IDEA, PyCharm, WebStorm) +- Active internet connection for AI service communication +- Plugin or configuration that recognizes `MarkdownListAction` -The `SelectionState` data class encapsulates the state of the selection and its context, including the selected text, selection offsets, entire document text, programming language, indentation, surrounding code elements, and the current project. +### Limitations -The `isLanguageSupported` method can be overridden by subclasses to specify which programming languages are supported by the action. +- The quality and relevance of the generated list items depend on the AI model's understanding of the context. +- Requires the document to be properly formatted as Markdown for accurate context recognition and bullet type matching. -The `defaultSelection` and `editSelection` methods can be overridden to customize the behavior for determining the default selection range and adjusting the selection range, respectively. +### Conclusion -Overall, this class provides a reusable and extensible framework for implementing actions that operate on selected text or a default selection in an editor, while handling the necessary context information and delegating the actual processing logic to subclasses. +The `MarkdownListAction` is a powerful tool for enhancing productivity and creativity when working with Markdown lists +in IntelliJ-based IDEs. By automating the generation and insertion of list items, it allows users to focus more on +content creation and less on manual list management. diff --git a/docs/action_readme.md b/docs/action_readme.md index 6762bdc2..a35e039d 100644 --- a/docs/action_readme.md +++ b/docs/action_readme.md @@ -25,19 +25,36 @@ time, and write better code. Get started today and explore the possibilities of # Actions - Action | Description | Usage | Dependencies | -------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| - `DescribeAction` | Generates natural language descriptions for selected code snippets using an AI model. | Select code, invoke action, description is inserted as a comment. | `com.github.simiacryptus.aicoder.actions.SelectionAction` | - `DocAction` | Generates documentation comments (e.g., JavaDoc, KDoc) for selected code blocks using an AI model. | Select code, invoke action, documentation is generated. | `com.github.simiacryptus.aicoder.actions.SelectionAction` | - `CustomEditAction` | Allows editing code using natural language instructions via an AI model. | Select code, invoke action, provide instructions, code is modified. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | - `CommentsAction` | Adds comments to each line of the selected code, explaining its functionality using an AI model. | Select code, invoke action, comments are added. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | - `InsertImplementationAction` | Generates code implementation based on a natural language specification or code comments using an AI model. | Select text or comment, invoke action, implementation is generated. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | - `PasteAction` | Converts the text content of the system clipboard from one programming language to another using an AI model. | Copy code, invoke action, converted code is returned. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | - `ImplementStubAction` | Generates code implementations for code stubs or declarations using an AI language model. | Select code stub, invoke action, implementation is generated. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | - `RecentCodeEditsAction` | Provides a menu for quickly applying recent custom code edits to the selected code. | Select code, invoke action, choose recent edit from menu. | `com.github.simiacryptus.aicoder.actions.ActionGroup`, `com.github.simiacryptus.aicoder.config.AppSettingsState` | - `RenameVariablesAction` | Suggests variable name renames for the selected code using an AI model. | Select code, invoke action, choose renames to apply. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | - `PrintTreeAction` | Prints the tree structure of a PsiFile (Program Structure Interface file) to the log. | Open file, invoke action, tree structure is printed to log. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.github.simiacryptus.aicoder.util.PsiUtil` | - `InternalCoderAction` | Launches a web-based interface for an internal coding agent that assists with coding tasks using natural language processing and machine learning models. | Invoke action, interact with coding agent via web interface. | `com.github.simiacryptus.aicoder.ApplicationEvents`, `com.simiacryptus.skyenet.apps.coding.CodingAgent`, `com.simiacryptus.skyenet.webui.application.*` | + Action | Description | Usage | Dependencies | + -----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| + `GenerateDocumentationAction` | Generates documentation for a set of code files using OpenAI's language model. | Right-click on a folder, select "Compile Documentation" | `com.github.simiacryptus.aicoder.actions.FileContextAction`, `com.simiacryptus.jopenai.proxy` | + `DescribeAction` | Generates natural language descriptions for selected code snippets using an AI model. | Select code, invoke action, description is inserted as a comment. | `com.github.simiacryptus.aicoder.actions.SelectionAction` | + `DocAction` | Generates documentation comments (e.g., JavaDoc, KDoc) for selected code blocks using an AI model. | Select code, invoke action, documentation is generated. | `com.github.simiacryptus.aicoder.actions.SelectionAction` | + `CustomEditAction` | Allows editing code using natural language instructions via an AI model. | Select code, invoke action, provide instructions, code is modified. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | + `CommentsAction` | Adds comments to each line of the selected code, explaining its functionality using an AI model. | Select code, invoke action, comments are added. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | + `InsertImplementationAction` | Generates code implementation based on a natural language specification or code comments using an AI model. | Select text or comment, invoke action, implementation is generated. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | + `PasteAction` | Converts the text content of the system clipboard from one programming language to another using an AI model. | Copy code, invoke action, converted code is returned. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | + `ImplementStubAction` | Generates code implementations for code stubs or declarations using an AI language model. | Select code stub, invoke action, implementation is generated. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | + `RecentCodeEditsAction` | Provides a menu for quickly applying recent custom code edits to the selected code. | Select code, invoke action, choose recent edit from menu. | `com.github.simiacryptus.aicoder.actions.ActionGroup`, `com.github.simiacryptus.aicoder.config.AppSettingsState` | + `RenameVariablesAction` | Suggests variable name renames for the selected code using an AI model. | Select code, invoke action, choose renames to apply. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | + `PrintTreeAction` | Prints the tree structure of a PsiFile (Program Structure Interface file) to the log. | Open file, invoke action, tree structure is printed to log. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.github.simiacryptus.aicoder.util.PsiUtil` | + `InternalCoderAction` | Launches a web-based interface for an internal coding agent that assists with coding tasks using natural language processing and machine learning models. | Invoke action, interact with coding agent via web interface. | `com.github.simiacryptus.aicoder.ApplicationEvents`, `com.simiacryptus.skyenet.apps.coding.CodingAgent`, `com.simiacryptus.skyenet.webui.application.*` | + `FileContextAction` | Provides a framework for creating file-based actions in an IntelliJ IDEA plugin. | Right-click on a file or folder, select the action from the menu. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.github.simiacryptus.aicoder.util.UITools` | + `SelectionAction` | Provides a base class for actions that operate on selected text in the editor. | Select text, invoke action, and the action processes the selection. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.github.simiacryptus.aicoder.util.ComputerLanguage` | + `AppendTextWithChatAction` | Appends text to the end of the user's selected text using OpenAI's chat API. | Select text, invoke action, and the text is appended. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | + `CreateFileFromTemplateAction` | Generates a new file based on an existing file and a natural language directive. | Right-click on a file, select the action, and provide a directive. | `com.github.simiacryptus.aicoder.actions.FileContextAction`, `com.simiacryptus.jopenai.proxy` | + `MultiStepPatchAction` | Provides an automated development assistant for code modification tasks using natural language instructions. | Select files or folders, invoke action, and provide instructions. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.simiacryptus.skyenet.webui.application.*` | + `CreateFileFromDescriptionAction` | Creates a new file based on a natural language description. | Invoke action, provide a description, and the file is created. | `com.github.simiacryptus.aicoder.actions.FileContextAction`, `com.simiacryptus.jopenai.proxy` | + `CodeChatAction` | Initiates a code chat session with an AI assistant for coding assistance. | Select code, invoke action, and chat with the AI assistant. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.simiacryptus.skyenet.webui.application.*` | + `VoiceToTextAction` | Allows users to dictate text into their code editor using speech recognition. | Invoke action, speak into the microphone, and text is inserted. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.simiacryptus.jopenai.proxy` | + `LineFilterChatAction` | Provides a chat interface for interacting with an AI assistant for coding assistance with line references and Markdown support. | Select code, invoke action, and chat with the AI assistant. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.simiacryptus.skyenet.webui.application.*` | + `MultiDiffChatAction` | Allows interacting with an AI assistant to modify multiple code files simultaneously using natural language instructions and code diffs. | Select files, invoke action, chat, and apply generated diffs. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.simiacryptus.skyenet.webui.application.*` | + `ReplaceWithSuggestionsAction` | Provides options for replacing selected text using an AI language model. | Select text, invoke action, and choose a replacement option. | `com.github.simiacryptus.aicoder.actions.SelectionAction`, `com.simiacryptus.jopenai.proxy` | + `RedoLast` | Repeats the last AI Coder action performed. | Invoke action to repeat the last action. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.github.simiacryptus.aicoder.config.AppSettingsState` | + `WebDevelopmentAssistantAction` | Provides a tool for developing web applications with AI assistance, including architecture design, code generation, and code review. | Right-click on a project or directory, select the action. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.simiacryptus.skyenet.webui.application.*` | + `MarkdownImplementActionGroup` | Provides a way to convert selected text in Markdown files into code snippets for various programming languages. | Select text in a Markdown file, choose the language from the menu. | `com.github.simiacryptus.aicoder.actions.ActionGroup`, `com.simiacryptus.jopenai.proxy` | + `PlanAheadAction` | Assists developers in task planning, code generation, documentation, and file management using AI models and a web UI. | Open a project, invoke action, and interact with the web UI. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.simiacryptus.skyenet.webui.application.*` | + `MarkdownListAction` | Generates new list items for an existing Markdown list using OpenAI's language model. | Select or place cursor in a list, invoke action to generate items. | `com.github.simiacryptus.aicoder.actions.BaseAction`, `com.simiacryptus.jopenai.proxy` | # code\DescribeAction.kt @@ -543,7 +560,7 @@ print the tree structure of the entity to the log. ```kotlin override fun handle(e: AnActionEvent) { - log.warn(PsiUtil.printTree(PsiUtil.getLargestContainedEntity(e)!!)) + log.warn(PsiUtil.printTree(PsiUtil.getLargestContainedEntity(e)!!)) } ``` @@ -554,7 +571,7 @@ enabled and can be triggered. ```kotlin override fun isEnabled(event: AnActionEvent): Boolean { - return AppSettingsState.instance.devActions + return AppSettingsState.instance.devActions } ``` @@ -564,7 +581,7 @@ The `PrintTreeAction` class has a companion object that initializes a logger ins ```kotlin companion object { - private val log = LoggerFactory.getLogger(PrintTreeAction::class.java) + private val log = LoggerFactory.getLogger(PrintTreeAction::class.java) } ``` @@ -690,20 +707,20 @@ Overall, this class provides a framework for creating file-based actions in an I extend this class and implement the `processSelection` method to define the specific behavior of the action. The class handles the UI interactions, file selection, and opening of generated files in the editor. -# generic\AppendAction.kt +# generic\AppendTextWithChatAction.kt -Sure, here's a README for the `AppendAction` class: +Sure, here's a README for the `AppendTextWithChatAction` class: -## AppendAction +## AppendTextWithChatAction -The `AppendAction` class is an implementation of the `SelectionAction` interface in +The `AppendTextWithChatAction` class is an implementation of the `SelectionAction` interface in the `com.github.simiacryptus.aicoder.actions.generic` package. It is designed to append text to the end of a user's selected text using OpenAI's chat API. ### Usage 1. The user selects a piece of text in the IDE. -2. The `AppendAction` is triggered (e.g., through a keyboard shortcut or menu item). +2. The `AppendTextWithChatAction` is triggered (e.g., through a keyboard shortcut or menu item). 3. The selected text is sent to the OpenAI chat API as a user prompt, along with a system prompt instructing the model to append text to the end of the user's prompt. 4. The API response is processed, and the original selected text is concatenated with the appended text from the API @@ -714,12 +731,13 @@ selected text using OpenAI's chat API. #### `getConfig(project: Project?): String` -This method is required by the `SelectionAction` interface but is not used in the `AppendAction` implementation. It +This method is required by the `SelectionAction` interface but is not used in the `AppendTextWithChatAction` +implementation. It returns an empty string. #### `processSelection(state: SelectionState, config: String?): String` -This is the main method of the `AppendAction` class. It performs the following steps: +This is the main method of the `AppendTextWithChatAction` class. It performs the following steps: 1. Retrieves the current app settings from `AppSettingsState.instance`. 2. Constructs a `ChatRequest` object with the following properties: @@ -736,7 +754,7 @@ This is the main method of the `AppendAction` class. It performs the following s ### Dependencies -The `AppendAction` class relies on the following dependencies: +The `AppendTextWithChatAction` class relies on the following dependencies: - `com.github.simiacryptus.aicoder.actions.SelectionAction` - `com.github.simiacryptus.aicoder.config.AppSettingsState` @@ -746,13 +764,14 @@ The `AppendAction` class relies on the following dependencies: Make sure these dependencies are properly imported and available in your project. -# generic\AnalogueFileAction.kt +# generic\GenerateRelatedFileAction.kt -Sure, here's a README for the `AnalogueFileAction` plugin: +Sure, here's a README for the `CreateFileFromTemplateAction` plugin: -## AnalogueFileAction +## CreateFileFromTemplateAction -The `AnalogueFileAction` is an IntelliJ IDEA plugin that allows you to generate a new file based on an existing file and +The `CreateFileFromTemplateAction` is an IntelliJ IDEA plugin that allows you to generate a new file based on an +existing file and a natural language directive. This can be useful for creating test cases, examples, or other related files based on your existing code. @@ -791,21 +810,23 @@ public class Calculator { ``` To generate test cases for this class, you can use the directive "Create test cases for the Calculator class" in -the `AnalogueFileAction` dialog. The plugin will generate a new file `CalculatorTest.java` with test cases for the `add` +the `CreateFileFromTemplateAction` dialog. The plugin will generate a new file `CalculatorTest.java` with test cases for +the `add` and `subtract` methods. ### Contributing -Contributions to the `AnalogueFileAction` plugin are welcome! If you find any issues or have suggestions for +Contributions to the `CreateFileFromTemplateAction` plugin are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on the project's GitHub repository. -# generic\AutoDevAction.kt +# generic\MultiStepPatchAction.kt Sure, here's a README file that documents the code you provided: -## AutoDevAction +## MultiStepPatchAction -`AutoDevAction` is an IntelliJ IDEA plugin action that provides an automated development assistant for code modification +`MultiStepPatchAction` is an IntelliJ IDEA plugin action that provides an automated development assistant for code +modification tasks. It allows users to provide natural language instructions, and the plugin generates an action plan, breaks it down into tasks, and applies code changes based on the instructions. @@ -831,7 +852,8 @@ into tasks, and applies code changes based on the instructions. ### Implementation Details -The `AutoDevAction` class extends `BaseAction` and handles the user interaction and plugin setup. It creates an instance +The `MultiStepPatchAction` class extends `BaseAction` and handles the user interaction and plugin setup. It creates an +instance of the `AutoDevApp` class, which manages the application server and user sessions. The `AutoDevApp` class is responsible for processing user messages and delegating the work to the `AutoDevAgent`. @@ -849,10 +871,11 @@ The plugin relies on the following external libraries: ### Contributing -Contributions to the AutoDevAction plugin are welcome! If you find any issues or have suggestions for improvements, +Contributions to the MultiStepPatchAction plugin are welcome! If you find any issues or have suggestions for +improvements, please open an issue or submit a pull request on the project's GitHub repository. -# generic\CreateFileAction.kt +# generic\CreateFileFromDescriptionAction.kt ``` File: README.md @@ -950,13 +973,13 @@ The `CodeChatAction` class relies on the following dependencies: Contributions to the `CodeChatAction` plugin are welcome. If you encounter any issues or have suggestions for improvements, please open an issue or submit a pull request on the project's repository. -# generic\DictationAction.kt +# generic\VoiceToTextAction.kt -Sure, here's a README file that explains the functionality of the `DictationAction` class: +Sure, here's a README file that explains the functionality of the `VoiceToTextAction` class: -## DictationAction +## VoiceToTextAction -The `DictationAction` class is an IntelliJ IDEA plugin action that allows users to dictate text into their code editor +The `VoiceToTextAction` class is an IntelliJ IDEA plugin action that allows users to dictate text into their code editor using speech recognition. When the action is triggered, it starts recording audio from the user's microphone and sends the recorded audio to an AI-powered speech-to-text service for transcription. The transcribed text is then inserted into the code editor at the current cursor position or replaces the selected text if there is a selection. @@ -995,7 +1018,7 @@ To use the dictation feature, follow these steps: 1. Open an IntelliJ IDEA project. 2. Open a code editor window. -3. Trigger the `DictationAction` by going to the `Tools` menu and selecting the "Dictation" option, or by using the +3. Trigger the `VoiceToTextAction` by going to the `Tools` menu and selecting the "Dictation" option, or by using the keyboard shortcut (if configured). 4. The status dialog window will appear, indicating that the recording and dictation process has started. 5. Start speaking into your microphone. The transcribed text will be inserted into the code editor at the current cursor @@ -1121,13 +1144,13 @@ The `DiffChatAction` relies on the following dependencies: Make sure to include these dependencies in your project for the `DiffChatAction` to work correctly. -# generic\DocumentationCompilerAction.kt +# generic\GenerateDocumentationAction.kt Sure, here's a README file that documents the code you provided: ## Documentation Compiler Action -The `DocumentationCompilerAction` is an IntelliJ IDEA plugin action that allows you to generate documentation for a set +The `GenerateDocumentationAction` is an IntelliJ IDEA plugin action that allows you to generate documentation for a set of code files using OpenAI's language model. It provides a user interface to select the files to process, specify the AI instruction for generating the documentation, and set the output file name. @@ -1148,7 +1171,7 @@ The generated documentation will be saved in the specified output file within th ### Implementation Details -The `DocumentationCompilerAction` class extends the `FileContextAction` class and provides the following functionality: +The `GenerateDocumentationAction` class extends the `FileContextAction` class and provides the following functionality: 1. `isEnabled(event: AnActionEvent)`: Checks if the selected file is a directory. If not, the action is disabled. 2. `getConfig(project: Project?, e: AnActionEvent)`: Displays the "Compile Documentation" dialog and collects the user @@ -1168,7 +1191,7 @@ the IntelliJ IDEA editor. ### Dependencies -The `DocumentationCompilerAction` relies on the following dependencies: +The `GenerateDocumentationAction` relies on the following dependencies: - `com.github.simiacryptus.aicoder.actions.FileContextAction` - `com.github.simiacryptus.aicoder.config.AppSettingsState` @@ -1248,13 +1271,14 @@ To install the `MultiDiffChatAction` plugin, follow these steps: If you find any issues or have suggestions for improvements, please feel free to open an issue or submit a pull request on the project's GitHub repository. -# generic\ReplaceOptionsAction.kt +# generic\ReplaceWithSuggestionsAction.kt -Sure, here's a README file that explains the purpose and usage of the `ReplaceOptionsAction` plugin: +Sure, here's a README file that explains the purpose and usage of the `ReplaceWithSuggestionsAction` plugin: -## ReplaceOptionsAction Plugin +## ReplaceWithSuggestionsAction Plugin -The `ReplaceOptionsAction` plugin is an IntelliJ IDEA plugin that provides a convenient way to replace selected text +The `ReplaceWithSuggestionsAction` plugin is an IntelliJ IDEA plugin that provides a convenient way to replace selected +text with one of the suggested options generated by an AI language model. This plugin leverages the OpenAI API to generate relevant and contextual suggestions based on the selected text and its surrounding context. @@ -1276,7 +1300,8 @@ relevant and contextual suggestions based on the selected text and its surroundi ### Configuration -The `ReplaceOptionsAction` plugin uses the OpenAI API to generate suggestions. You need to provide your OpenAI API key +The `ReplaceWithSuggestionsAction` plugin uses the OpenAI API to generate suggestions. You need to provide your OpenAI +API key in the plugin settings. Additionally, you can configure the following options: - **Default Chat Model**: Specify the AI language model to use for generating suggestions. @@ -1289,7 +1314,8 @@ in the plugin settings. Additionally, you can configure the following options: ### Contributing -Contributions to the `ReplaceOptionsAction` plugin are welcome! If you encounter any issues or have suggestions for +Contributions to the `ReplaceWithSuggestionsAction` plugin are welcome! If you encounter any issues or have suggestions +for improvements, please open an issue or submit a pull request on the project's GitHub repository. ### License @@ -1373,7 +1399,7 @@ This README provides an overview of the AI Coder plugin for IntelliJ IDEA, inclu instructions, usage examples, contributing guidelines, license information, and support contact details. Feel free to customize it further based on your specific requirements. -# generic\WebDevAction.kt +# generic\WebDevelopmentAssistantAction.kt ```markdown @@ -1473,7 +1499,7 @@ an issue or submit a pull request on the project's GitHub repository. This plugin is released under the [MIT License](LICENSE). -# generic\TaskRunnerAction.kt +# generic\PlanAheadAction.kt ```markdown @@ -1650,5 +1676,4 @@ Special thanks to the developers and contributors of these projects. This README provides an overview of the AI Coder Plugin, its features, usage instructions, contributing guidelines, license information, and acknowledgments. Feel free to modify it as needed to better fit your project's specific -details. - +details. \ No newline at end of file diff --git a/docs/actions.md b/docs/actions.md index 944661f1..eb51916f 100644 --- a/docs/actions.md +++ b/docs/actions.md @@ -785,7 +785,7 @@ The server's running state is monitored in a separate thread, which allows for a The `AppServer` plugin provides a robust and flexible way to integrate web applications, including real-time WebSocket applications, into your development environment. By following the instructions outlined in this documentation, you can effectively manage and interact with web applications within your project. -# generic\AnalogueFileAction.kt +# generic\GenerateRelatedFileAction.kt ## Analogue File Action Plugin Documentation @@ -968,17 +968,17 @@ Before you can use the Code Chat Plugin, ensure you have the following: The Code Chat Plugin offers a powerful way to enhance collaboration and streamline the code review process directly within your IDE. By following this guide, you should be well-equipped to start using the plugin to its full potential. Happy coding and collaborating! -# generic\CreateFileAction.kt +# generic\CreateFileFromDescriptionAction.kt -## CreateFileAction Plugin Documentation +## CreateFileFromDescriptionAction Plugin Documentation -The `CreateFileAction` plugin is a powerful tool designed to automate the process of file creation within a project, leveraging natural language directives to generate the necessary code. This document provides a comprehensive guide on how to use the `CreateFileAction` plugin effectively. +The `CreateFileFromDescriptionAction` plugin is a powerful tool designed to automate the process of file creation within a project, leveraging natural language directives to generate the necessary code. This document provides a comprehensive guide on how to use the `CreateFileFromDescriptionAction` plugin effectively. ### Overview -The `CreateFileAction` plugin integrates with the project environment to interpret natural language instructions and generate files accordingly. It utilizes the OpenAI API to understand the directives and create files with the specified content and at the desired location within the project structure. +The `CreateFileFromDescriptionAction` plugin integrates with the project environment to interpret natural language instructions and generate files accordingly. It utilizes the OpenAI API to understand the directives and create files with the specified content and at the desired location within the project structure. ### Key Components @@ -999,7 +999,7 @@ The `CreateFileAction` plugin integrates with the project environment to interpr 1. **Configure the Directive**: Access the `SettingsUI` component and input your directive in the provided text area. For example, "Create a default log4j configuration file". 2. **Select the Target Location**: In your project, select the location where you want the new file to be created. This selection will determine the base path for the new file. -3. **Execute the Action**: Run the `CreateFileAction` plugin. It will process your directive and the selected location to generate and create the new file accordingly. +3. **Execute the Action**: Run the `CreateFileFromDescriptionAction` plugin. It will process your directive and the selected location to generate and create the new file accordingly. ### Example @@ -1008,7 +1008,7 @@ Suppose you want to create a new log4j configuration file in your Java project. 1. Open the `SettingsUI` and input the directive: "Create a default log4j configuration file". 2. Select the `src/main/resources` directory in your project as the target location. -3. Execute the `CreateFileAction`. The plugin will then generate a log4j configuration file based on your directive and place it in the specified directory. +3. Execute the `CreateFileFromDescriptionAction`. The plugin will then generate a log4j configuration file based on your directive and place it in the specified directory. ### Handling Existing Files @@ -1018,17 +1018,17 @@ If the plugin detects that the generated file's intended path already exists, it ### Conclusion -The `CreateFileAction` plugin offers a convenient and efficient way to automate file creation within your projects, leveraging natural language processing to interpret directives and generate the necessary files. By following the steps outlined in this document, you can harness the power of this plugin to streamline your development workflow. +The `CreateFileFromDescriptionAction` plugin offers a convenient and efficient way to automate file creation within your projects, leveraging natural language processing to interpret directives and generate the necessary files. By following the steps outlined in this document, you can harness the power of this plugin to streamline your development workflow. -# generic\AppendAction.kt +# generic\AppendTextWithChatAction.kt -## AppendAction Plugin Documentation +## AppendTextWithChatAction Plugin Documentation ### Overview -The `AppendAction` plugin is designed to enhance your coding experience by allowing you to automatically append generated text to a selected piece of text within your code editor. This functionality is particularly useful for developers looking for quick ways to extend their code snippets based on AI-generated suggestions. +The `AppendTextWithChatAction` plugin is designed to enhance your coding experience by allowing you to automatically append generated text to a selected piece of text within your code editor. This functionality is particularly useful for developers looking for quick ways to extend their code snippets based on AI-generated suggestions. ### Features @@ -1047,16 +1047,16 @@ The `AppendAction` plugin is designed to enhance your coding experience by allow ### Usage -To use the `AppendAction` plugin, follow these steps: +To use the `AppendTextWithChatAction` plugin, follow these steps: 1. **Select Text**: Highlight the text in your code editor that you want to append generated text to. -2. **Activate AppendAction**: Use the designated shortcut or menu option to activate the `AppendAction` plugin. +2. **Activate AppendTextWithChatAction**: Use the designated shortcut or menu option to activate the `AppendTextWithChatAction` plugin. 3. **Review and Accept**: The plugin will automatically append the AI-generated text to your selection. Review the appended text and make any necessary adjustments. ### Configuration -The behavior of the `AppendAction` plugin can be customized through the `AppSettingsState`. Key settings include: +The behavior of the `AppendTextWithChatAction` plugin can be customized through the `AppSettingsState`. Key settings include: - **Default Chat Model**: Specifies the AI model used for generating text. This can be adjusted to use different models based on your preference or the specific needs of your project. - **Temperature**: Controls the creativity of the generated text. A higher temperature results in more creative (but potentially less predictable) outputs, while a lower temperature produces more conservative and predictable text. @@ -1070,19 +1070,19 @@ The behavior of the `AppendAction` plugin can be customized through the `AppSett ### Conclusion -The `AppendAction` plugin offers a powerful way to extend your code with AI-generated text, streamlining your development process and sparking creativity. By customizing the plugin settings, you can tailor the text generation to meet your specific needs and preferences. +The `AppendTextWithChatAction` plugin offers a powerful way to extend your code with AI-generated text, streamlining your development process and sparking creativity. By customizing the plugin settings, you can tailor the text generation to meet your specific needs and preferences. -# generic\DictationAction.kt +# generic\VoiceToTextAction.kt -## DictationAction Plugin Documentation +## VoiceToTextAction Plugin Documentation -The `DictationAction` plugin is designed to enhance your coding experience by allowing you to dictate code and comments directly into your IDE. This document provides an overview of the plugin's functionality, setup instructions, and usage guidelines. +The `VoiceToTextAction` plugin is designed to enhance your coding experience by allowing you to dictate code and comments directly into your IDE. This document provides an overview of the plugin's functionality, setup instructions, and usage guidelines. ### Overview -The `DictationAction` plugin captures audio through your microphone, processes the audio to convert speech to text, and then inserts the transcribed text into your code editor at the current cursor position or replaces the selected text. It operates in the background, starting with a simple action trigger and stopping when you close a specific dialog window. +The `VoiceToTextAction` plugin captures audio through your microphone, processes the audio to convert speech to text, and then inserts the transcribed text into your code editor at the current cursor position or replaces the selected text. It operates in the background, starting with a simple action trigger and stopping when you close a specific dialog window. ### Features @@ -1095,7 +1095,7 @@ The `DictationAction` plugin captures audio through your microphone, processes t ### Prerequisites -Before using the `DictationAction` plugin, ensure you have: +Before using the `VoiceToTextAction` plugin, ensure you have: - A compatible IDE (IntelliJ-based IDEs). - A working microphone set up and configured on your system. @@ -1104,7 +1104,7 @@ Before using the `DictationAction` plugin, ensure you have: ### Installation -1. Download the `DictationAction` plugin from the plugin marketplace or the provided source. +1. Download the `VoiceToTextAction` plugin from the plugin marketplace or the provided source. 2. In your IDE, navigate to `Settings` > `Plugins`. 3. Click on `Install Plugin from Disk...` and select the downloaded plugin file. 4. Restart your IDE to activate the plugin. @@ -1115,7 +1115,7 @@ Before using the `DictationAction` plugin, ensure you have: To start dictating: 1. Ensure your microphone is on and properly configured. -2. Trigger the `DictationAction` from the IDE's action menu or use the assigned shortcut. +2. Trigger the `VoiceToTextAction` from the IDE's action menu or use the assigned shortcut. 3. A dialog titled "Dictation" will appear, indicating that dictation is active. Keep this dialog open while dictating. 4. Speak clearly into your microphone. Your spoken words will be transcribed and inserted into your editor in real-time. 5. To stop dictation, simply close the "Dictation" dialog window. @@ -1135,9 +1135,9 @@ For support, feature requests, or to report bugs, please visit the plugin's GitH ### Conclusion -The `DictationAction` plugin offers a convenient way to enhance your coding efficiency through voice commands. By following the setup instructions and usage guidelines provided in this document, you can seamlessly integrate dictation into your development workflow. +The `VoiceToTextAction` plugin offers a convenient way to enhance your coding efficiency through voice commands. By following the setup instructions and usage guidelines provided in this document, you can seamlessly integrate dictation into your development workflow. -# generic\DocumentationCompilerAction.kt +# generic\GenerateDocumentationAction.kt #### Documentation Compiler Action Plugin @@ -1435,15 +1435,15 @@ For support, feature requests, or to report bugs, please visit the plugin's GitH This documentation aims to provide you with all the necessary information to get started with the Markdown List Action plugin. Enhance your Markdown editing experience by leveraging the power of AI to generate list items effortlessly. -# generic\ReplaceOptionsAction.kt +# generic\ReplaceWithSuggestionsAction.kt -## ReplaceOptionsAction Plugin Documentation +## ReplaceWithSuggestionsAction Plugin Documentation ### Overview -The `ReplaceOptionsAction` plugin is designed to enhance your coding experience within the IntelliJ IDEA environment by providing smart text replacement suggestions. Leveraging advanced AI models, this plugin analyzes the context of your selected text and offers a list of suggestions to replace it, aiming to improve code quality, readability, or simply to offer creative alternatives. +The `ReplaceWithSuggestionsAction` plugin is designed to enhance your coding experience within the IntelliJ IDEA environment by providing smart text replacement suggestions. Leveraging advanced AI models, this plugin analyzes the context of your selected text and offers a list of suggestions to replace it, aiming to improve code quality, readability, or simply to offer creative alternatives. ### Features @@ -1457,7 +1457,7 @@ The `ReplaceOptionsAction` plugin is designed to enhance your coding experience ### How to Use 1. **Select Text:** Begin by selecting the text in your code that you wish to replace. -2. **Activate Action:** Trigger the `ReplaceOptionsAction` by using its assigned shortcut or by finding it in the context menu. +2. **Activate Action:** Trigger the `ReplaceWithSuggestionsAction` by using its assigned shortcut or by finding it in the context menu. 3. **Choose Replacement:** A dialog will appear with a list of suggestions. Select the one that best fits your needs and confirm your choice. 4. **Review Changes:** The selected text in your code will be replaced with your chosen suggestion. Review the change to ensure it meets your expectations. @@ -1471,7 +1471,7 @@ The `ReplaceOptionsAction` plugin is designed to enhance your coding experience ### Customization -To tailor the behavior of the `ReplaceOptionsAction` plugin to your preferences, you can adjust the settings in `AppSettingsState`. This includes: +To tailor the behavior of the `ReplaceWithSuggestionsAction` plugin to your preferences, you can adjust the settings in `AppSettingsState`. This includes: - **Default Chat Model:** Choose the AI model that best suits your coding style or the specific language/framework you are working with. - **Temperature:** Adjust the creativity level of the suggestions. A higher temperature results in more creative (but potentially less accurate) suggestions, while a lower temperature favors more conservative and contextually accurate options. @@ -1485,7 +1485,7 @@ To tailor the behavior of the `ReplaceOptionsAction` plugin to your preferences, ### Conclusion -The `ReplaceOptionsAction` plugin offers a powerful way to enhance your coding experience by integrating AI-powered text replacement suggestions directly into your workflow. By understanding and utilizing its features, you can significantly improve the efficiency and quality of your code writing process. +The `ReplaceWithSuggestionsAction` plugin offers a powerful way to enhance your coding experience by integrating AI-powered text replacement suggestions directly into your workflow. By understanding and utilizing its features, you can significantly improve the efficiency and quality of your code writing process. # SelectionAction.kt diff --git a/docs/code_review.md b/docs/code_review.md index 6fb7f447..e1e941a2 100644 --- a/docs/code_review.md +++ b/docs/code_review.md @@ -779,10 +779,10 @@ application contexts. It demonstrates good practices in Kotlin programming, thre some enhancements, especially in error recovery and configuration flexibility, it could be an even more robust solution for real-world applications. -# actions\generic\AnalogueFileAction.kt +# actions\generic\GenerateRelatedFileAction.kt -This Kotlin code defines a class `AnalogueFileAction` that extends `FileContextAction` with a specific settings -type, `AnalogueFileAction.Settings`. It is designed to work within an IntelliJ IDEA plugin, leveraging the IntelliJ +This Kotlin code defines a class `CreateFileFromTemplateAction` that extends `FileContextAction` with a specific settings +type, `CreateFileFromTemplateAction.Settings`. It is designed to work within an IntelliJ IDEA plugin, leveraging the IntelliJ Platform SDK to interact with the IDE's file system, UI, and project structure. The action appears to be aimed at generating new files based on a directive provided by the user, possibly using an AI model to generate the content of the new file. Below is a detailed review of the code, highlighting its structure, functionality, and areas for potential @@ -790,7 +790,7 @@ improvement. #### Structure and Functionality -- **Class Hierarchy and Data Classes**: The `AnalogueFileAction` class inherits from `FileContextAction`, indicating +- **Class Hierarchy and Data Classes**: The `CreateFileFromTemplateAction` class inherits from `FileContextAction`, indicating it's an action related to file context within the IDE. It uses several data classes (`ProjectFile`, `SettingsUI`, `UserSettings`, `Settings`) for managing its configuration and UI. @@ -834,13 +834,13 @@ improvement. #### Conclusion -The `AnalogueFileAction` class is a sophisticated piece of an IntelliJ IDEA plugin that leverages AI to generate new +The `CreateFileFromTemplateAction` class is a sophisticated piece of an IntelliJ IDEA plugin that leverages AI to generate new files based on user directives. While the functionality is promising, incorporating error handling, improving performance considerations, and enhancing code readability could make it more robust and user-friendly. -# actions\generic\AppendAction.kt +# actions\generic\AppendTextWithChatAction.kt -This Kotlin class, `AppendAction`, is part of a package designed to work within an IntelliJ platform-based IDE, +This Kotlin class, `AppendTextWithChatAction`, is part of a package designed to work within an IntelliJ platform-based IDE, leveraging the OpenAI API to enhance coding or text editing tasks. It extends `SelectionAction`, indicating it operates on selections within the IDE, processing them, and returning a `String` result. Below is a detailed review of its components and functionality: @@ -854,7 +854,7 @@ its components and functionality: #### Class Definition -- `AppendAction` inherits from `SelectionAction`, a generic type indicating this action works with text +- `AppendTextWithChatAction` inherits from `SelectionAction`, a generic type indicating this action works with text selections and returns a `String`. #### Overridden Methods @@ -892,7 +892,7 @@ its components and functionality: - **User Feedback**: In its current form, the action does not provide feedback to the user if the API call fails or returns an empty response, which could be improved for a better user experience. -Overall, `AppendAction` demonstrates a practical application of integrating AI-powered functionalities within +Overall, `AppendTextWithChatAction` demonstrates a practical application of integrating AI-powered functionalities within development tools, with room for enhancements in configurability, robustness, and user interaction. # actions\generic\CodeChatAction.kt @@ -966,10 +966,10 @@ structure, functionality, and some suggestions for improvement. Overall, the `CodeChatAction` class provides a solid foundation for the Code Chat feature, with room for enhancements in error handling, security, and code documentation. -# actions\generic\CreateFileAction.kt +# actions\generic\CreateFileFromDescriptionAction.kt -This Kotlin code defines a class `CreateFileAction` that extends `FileContextAction` with a specific setting -type `CreateFileAction.Settings`. The class is designed to automate the process of creating a new file within a project +This Kotlin code defines a class `CreateFileFromDescriptionAction` that extends `FileContextAction` with a specific setting +type `CreateFileFromDescriptionAction.Settings`. The class is designed to automate the process of creating a new file within a project based on a directive provided by the user. The directive is processed using an AI model to generate the content and name of the new file. Below is a detailed review of the code, highlighting its structure, functionality, and areas for potential improvement. @@ -979,7 +979,7 @@ potential improvement. - `ProjectFile`: A simple data class holding the path and code of the generated file. - `SettingsUI`: A class that defines the UI component for inputting the directive. It uses a `JTextArea` to capture the directive from the user. -- `Settings`: A class that holds the settings for the `CreateFileAction`, currently only containing a `directive` +- `Settings`: A class that holds the settings for the `CreateFileFromDescriptionAction`, currently only containing a `directive` string. - `processSelection`: The main method that processes the user's selection and generates a new file based on the provided directive. @@ -1025,13 +1025,13 @@ potential improvement. #### Conclusion -The `CreateFileAction` class is a sophisticated piece of code designed to leverage AI for automating file creation based +The `CreateFileFromDescriptionAction` class is a sophisticated piece of code designed to leverage AI for automating file creation based on natural language directives. While the core functionality is promising, attention to error handling, flexibility, and documentation could enhance its robustness, usability, and maintainability. -# actions\generic\DictationAction.kt +# actions\generic\VoiceToTextAction.kt -This Kotlin code defines a class `DictationAction` that extends `BaseAction` and is designed to integrate with an +This Kotlin code defines a class `VoiceToTextAction` that extends `BaseAction` and is designed to integrate with an IntelliJ platform-based IDE to provide a dictation feature. The action, when triggered, captures audio from the user's microphone, processes the audio to convert speech to text, and inserts the transcribed text into the IDE's active editor. The code is structured into several key components and utilizes multithreading to handle audio recording, @@ -1040,7 +1040,7 @@ functionalities of the code: #### Main Components: -1. **DictationAction Class:** +1. **VoiceToTextAction Class:** - The `handle` method is the entry point for the action. It sets up threads for audio recording, audio processing, and speech-to-text conversion. - It uses a status dialog to allow the user to stop the dictation process by closing the window. @@ -1086,7 +1086,7 @@ functionalities of the code: - **Documentation:** The code lacks comments and documentation. Adding comprehensive documentation and comments would make the code more maintainable and easier to understand for other developers. -Overall, the `DictationAction` class provides a solid foundation for integrating dictation functionality into an IDE. +Overall, the `VoiceToTextAction` class provides a solid foundation for integrating dictation functionality into an IDE. With some enhancements to error handling, resource management, and user feedback, it could be a very useful tool for developers. @@ -1151,9 +1151,9 @@ Overall, `DiffChatAction` is an innovative feature that combines code review and enhancing collaboration among developers. However, attention to security, performance, and user experience is crucial for its successful implementation. -# actions\generic\DocumentationCompilerAction.kt +# actions\generic\GenerateDocumentationAction.kt -This Kotlin code defines a class `DocumentationCompilerAction` that extends `FileContextAction` with a specific settings +This Kotlin code defines a class `GenerateDocumentationAction` that extends `FileContextAction` with a specific settings class. The action is designed for use within an IntelliJ platform-based IDE, where it compiles documentation for selected files or directories by transforming their content using an AI model provided by the `com.simiacryptus.jopenai` package. Here's a detailed review of the code, highlighting its structure, functionality, and areas for potential @@ -1212,7 +1212,7 @@ improvement. and functionality of key methods and decisions. Adding documentation comments would improve readability and maintainability. -Overall, the `DocumentationCompilerAction` class demonstrates a sophisticated integration of AI-based content +Overall, the `GenerateDocumentationAction` class demonstrates a sophisticated integration of AI-based content transformation within an IDE plugin. With enhancements in error handling, resource management, and user feedback, it could provide a powerful tool for automating documentation compilation. @@ -1271,9 +1271,9 @@ Here's a breakdown and review of the key components of this code: Overall, the code is well-structured and serves a clear purpose within the context of an IntelliJ plugin. With minor improvements, especially related to null safety and error handling, it could be even more robust. -# actions\generic\ReplaceOptionsAction.kt +# actions\generic\ReplaceWithSuggestionsAction.kt -This Kotlin code defines a class `ReplaceOptionsAction` that extends `SelectionAction`. It's designed to work +This Kotlin code defines a class `ReplaceWithSuggestionsAction` that extends `SelectionAction`. It's designed to work within an IDE environment, likely as part of a plugin, where it interacts with a virtual API to suggest text replacements for a selected portion of text in the editor. The class and its components are structured to integrate with IntelliJ's action system and a custom virtual API for text suggestions. Below is a detailed review of its components and @@ -1281,7 +1281,7 @@ functionality: #### Class Structure and Inheritance -- `ReplaceOptionsAction` inherits from `SelectionAction`, indicating it performs an action based on a text +- `ReplaceWithSuggestionsAction` inherits from `SelectionAction`, indicating it performs an action based on a text selection and returns a `String`. - It defines an internal interface `VirtualAPI` for interacting with a text suggestion service. @@ -1327,7 +1327,7 @@ functionality: Ensuring that this utility handles various edge cases, like no available choices or user cancellation, is essential for a smooth user experience. -Overall, the `ReplaceOptionsAction` class is a well-structured piece of code designed for extending IDE functionality +Overall, the `ReplaceWithSuggestionsAction` class is a well-structured piece of code designed for extending IDE functionality with text suggestion capabilities. Enhancing it with comments, error handling, and possibly revisiting the `getConfig` method's purpose could make it more robust and maintainable. diff --git a/docs/coding_standards.md b/docs/coding_standards.md new file mode 100644 index 00000000..23861758 --- /dev/null +++ b/docs/coding_standards.md @@ -0,0 +1,70 @@ +# Coding Standards Document for Kotlin and Action Development + +This document outlines the coding standards and best practices derived from the provided Kotlin code examples. It aims +to ensure consistency, readability, and maintainability of the codebase. + +## General Principles + +1. **Consistency**: Adhere to the established coding conventions and patterns throughout the project. +2. **Readability**: Write code that is easy to read and understand by others, including proper naming and commenting. +3. **Maintainability**: Write modular, reusable code with clear separation of concerns to facilitate future updates and + maintenance. + +## Naming Conventions + +- **Classes and Interfaces**: Use PascalCase and be descriptive. Example: `StaticAppSettingsConfigurable`. +- **Functions and Variables**: Use camelCase and be descriptive. Example: `buildComponent`. +- **Constants**: Use UPPER_SNAKE_CASE. Example: `API_PROVIDER`. +- **Packages**: Use lowercase and avoid underscores. Example: `com.github.simiacryptus.aicoder.util`. + +## Formatting + +- **Indentation**: Use 4 spaces for indentation, not tabs. +- **Braces**: Place opening braces on the same line as the statement and closing braces on their own line. +- **Line Length**: Aim to keep lines under 120 characters for better readability. +- **Spacing**: Use spaces after commas, colons, and semicolons. Avoid spaces before commas. + +## Comments and Documentation + +- **Function Comments**: Document all public functions with KDoc, explaining purpose, parameters, return values, and + exceptions. +- **Inline Comments**: Use inline comments sparingly to explain complex logic or decisions that aren't immediately + clear. +- **TODOs**: Mark incomplete or temporary code with `TODO` comments, including a brief description. + +## Error Handling + +- Use try-catch blocks for error handling and log exceptions using a project-specific logger. +- Avoid swallowing exceptions unless absolutely necessary. If an exception is caught and not rethrown, document the + reason. + +## Kotlin-Specific Practices + +- **Null Safety**: Leverage Kotlin's null safety features. Use nullable types (`?`) and safe calls (`?.`) appropriately. +- **Data Classes**: Use data classes for simple data holding objects. +- **Extension Functions**: Use extension functions to add functionality to existing classes without inheritance. +- **Scope Functions**: Use scope functions (`let`, `apply`, `run`, `with`, `also`) for more concise and readable code, + especially when working with nullable types or initializing objects. + +## UI Development + +- **Layout Management**: Use appropriate layout managers to handle component layout in a flexible and responsive manner. +- **Event Handling**: Use lambda expressions or function references for concise event listener implementation. +- **Component Initialization**: Initialize UI components in a separate function or block to keep the UI code organized. + +## Action Development + +- **Action Registration**: Register actions in the appropriate action groups and ensure they are correctly enabled or + disabled based on the context. +- **Background Tasks**: Use background threads for long-running tasks to keep the UI responsive. Ensure thread safety + when accessing shared resources. +- **Logging**: Use a consistent logging approach across actions for debugging and error reporting. + +## Version Control + +- **Commit Messages**: Write clear, concise commit messages that describe the changes and their purpose. +- **Code Reviews**: Submit all changes for code review before merging to ensure adherence to standards and catch + potential issues. + +By following these coding standards and best practices, developers can contribute to a codebase that is clean, +efficient, and easy to work with. \ No newline at end of file diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..e76f1bed --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,88 @@ +Sure, here's a draft README.md file explaining the configuration options in the `AppSettingsState` class: + +# AI Coder Configuration + +The `AppSettingsState` class contains configuration settings for the AI Coder plugin. Here's an explanation of each +setting: + +## `temperature` + +- **Type:** `Double` +- **Default:** `0.1` +- This controls the randomness of the AI model's output. Higher values (up to 1.0) make the output more random and + creative, while lower values make it more focused and deterministic. + +## `modelName` + +- **Type:** `String` +- **Default:** `"gpt-3.5-turbo"` +- The name of the AI model to use. The default is the GPT-3.5 Turbo model. + +## `listeningPort` + +- **Type:** `Int` +- **Default:** `8081` +- The local port to listen on for API requests. + +## `listeningEndpoint` + +- **Type:** `String` +- **Default:** `"localhost"` +- The local hostname or IP address to listen on for API requests. + +## `humanLanguage` + +- **Type:** `String` +- **Default:** `"English"` +- The language to use for user prompts and AI responses. + +## `apiThreads` + +- **Type:** `Int` +- **Default:** `4` +- The number of threads to use for processing API requests. + +## `apiBase` + +- **Type:** `Map?` +- **Default:** `mapOf("OpenAI" to "https://api.openai.com/v1")` +- A map of provider names to base API URLs. + +## `apiKey` + +- **Type:** `Map?` +- **Default:** `mapOf("OpenAI" to "")` +- A map of provider names to API keys. + +## `modalTasks` + +- **Type:** `Boolean` +- **Default:** `false` +- Whether to use modal tasks (blocking UI) for AI requests. + +## `suppressErrors` + +- **Type:** `Boolean` +- **Default:** `false` +- Whether to suppress error messages from the AI API. + +## `apiLog` + +- **Type:** `Boolean` +- **Default:** `false` +- Whether to log API requests and responses. + +## `devActions` + +- **Type:** `Boolean` +- **Default:** `false` +- Whether to enable developer actions (e.g., editing requests). + +## `editRequests` + +- **Type:** `Boolean` +- **Default:** `false` +- Whether to allow editing of AI requests before sending them. + +The `AppSettingsState` class also includes an `editorActions` and `fileActions` registry for configuring custom actions, +as well as a `recentCommands` map for storing recent AI commands. \ No newline at end of file diff --git a/docs/feature_roadmap.md b/docs/feature_roadmap.md index 179698bd..02ab4dea 100644 --- a/docs/feature_roadmap.md +++ b/docs/feature_roadmap.md @@ -785,7 +785,7 @@ Creating a feature development roadmap for the `CodeChatAction` class involves o This roadmap aims to guide the development of the `CodeChatAction` class and its associated features, ensuring continuous improvement and adaptation to user needs and technological advancements. -# kotlin\com\github\simiacryptus\aicoder\actions\generic\AnalogueFileAction.kt +# kotlin\com\github\simiacryptus\aicoder\actions\generic\GenerateRelatedFileAction.kt The code provided is part of a larger project aimed at integrating AI-driven functionalities into an IDE, specifically for generating analogue files based on directives. The roadmap for developing and enhancing this feature can be structured into several key phases, each focusing on different aspects of the project, from foundational setup to advanced features and optimizations. Below is a proposed feature development roadmap: @@ -830,13 +830,13 @@ The code provided is part of a larger project aimed at integrating AI-driven fun This roadmap is designed to be flexible, allowing for adjustments based on user feedback, technological advancements, and changes in project priorities. -# kotlin\com\github\simiacryptus\aicoder\actions\generic\AppendAction.kt +# kotlin\com\github\simiacryptus\aicoder\actions\generic\AppendTextWithChatAction.kt -Creating a feature development roadmap for the `AppendAction` class within the context of enhancing an IDE plugin for AI-assisted coding involves outlining a series of steps or phases. This roadmap aims to guide the development, from initial enhancements to more sophisticated features, ensuring the plugin remains useful, efficient, and user-friendly. Here's a proposed roadmap: +Creating a feature development roadmap for the `AppendTextWithChatAction` class within the context of enhancing an IDE plugin for AI-assisted coding involves outlining a series of steps or phases. This roadmap aims to guide the development, from initial enhancements to more sophisticated features, ensuring the plugin remains useful, efficient, and user-friendly. Here's a proposed roadmap: #### Phase 1: Initial Enhancements and Fixes -- **Bug Fixes:** Address any known bugs in the `AppendAction` class to ensure stability. +- **Bug Fixes:** Address any known bugs in the `AppendTextWithChatAction` class to ensure stability. - **Performance Optimization:** Improve the response time of the AI model by optimizing the API call and handling of the response. - **User Interface Improvements:** Enhance the user experience by providing clear feedback when the action is triggered, such as a loading indicator or a success message. @@ -850,7 +850,7 @@ Creating a feature development roadmap for the `AppendAction` class within the c #### Phase 3: Advanced Features - **Multi-Language Support:** Extend the functionality to support multiple programming languages, adapting the action based on the language of the current file. - **Interactive Mode:** Implement an interactive mode where users can iteratively refine the appended text with the help of the AI, providing feedback or corrections. -- **Version Control Integration:** Integrate with version control systems to allow users to easily commit changes made by the `AppendAction`, including automatic commit messages generated by the AI. +- **Version Control Integration:** Integrate with version control systems to allow users to easily commit changes made by the `AppendTextWithChatAction`, including automatic commit messages generated by the AI. #### Phase 4: Collaboration and Sharing @@ -870,11 +870,11 @@ Creating a feature development roadmap for the `AppendAction` class within the c - **Integration with Other Tools:** Look into integrating the plugin with other development tools and platforms, enhancing its utility and accessibility. - **Adaptive Learning:** Implement machine learning techniques to allow the plugin to learn from user interactions and improve its suggestions over time. -This roadmap provides a structured approach to developing the `AppendAction` class and related features, ensuring continuous improvement and adaptation to user needs. +This roadmap provides a structured approach to developing the `AppendTextWithChatAction` class and related features, ensuring continuous improvement and adaptation to user needs. -# kotlin\com\github\simiacryptus\aicoder\actions\generic\CreateFileAction.kt +# kotlin\com\github\simiacryptus\aicoder\actions\generic\CreateFileFromDescriptionAction.kt -The `CreateFileAction` class is part of a larger project aimed at automating file creation within a software development environment. This class specifically focuses on generating files based on natural language directives, leveraging an AI model to interpret these directives and create appropriate file content and paths. Below is a proposed feature development roadmap to enhance the capabilities and performance of the `CreateFileAction` class. +The `CreateFileFromDescriptionAction` class is part of a larger project aimed at automating file creation within a software development environment. This class specifically focuses on generating files based on natural language directives, leveraging an AI model to interpret these directives and create appropriate file content and paths. Below is a proposed feature development roadmap to enhance the capabilities and performance of the `CreateFileFromDescriptionAction` class. #### Phase 1: Core Functionality Improvement @@ -909,7 +909,7 @@ The `CreateFileAction` class is part of a larger project aimed at automating fil - **Security Audits**: Regularly conduct security audits to identify and mitigate potential vulnerabilities, especially those related to handling and storing project files. - **Compliance Checks**: Integrate compliance checks to ensure that generated files adhere to industry standards and regulations relevant to the project's domain. -This roadmap outlines a comprehensive approach to developing the `CreateFileAction` class into a robust tool that enhances productivity and streamlines the file creation process in software development projects. Each phase builds upon the previous one, gradually introducing new features and improvements based on user feedback and technological advancements. +This roadmap outlines a comprehensive approach to developing the `CreateFileFromDescriptionAction` class into a robust tool that enhances productivity and streamlines the file creation process in software development projects. Each phase builds upon the previous one, gradually introducing new features and improvements based on user feedback and technological advancements. # kotlin\com\github\simiacryptus\aicoder\actions\dev\InternalCoderAction.kt @@ -1015,12 +1015,12 @@ Developing a feature, especially for a software project like an IntelliJ plugin, #### Conclusion This roadmap provides a structured approach to enhancing the "RedoLast" action, focusing on user needs, technical excellence, and continuous improvement. By following these phases, the development team can ensure a successful feature enhancement that meets or exceeds user expectations. -# kotlin\com\github\simiacryptus\aicoder\actions\generic\DocumentationCompilerAction.kt +# kotlin\com\github\simiacryptus\aicoder\actions\generic\GenerateDocumentationAction.kt -#### Feature Development Roadmap for DocumentationCompilerAction +#### Feature Development Roadmap for GenerateDocumentationAction -The `DocumentationCompilerAction` class is a sophisticated component designed to automate the process of compiling documentation from code files within a project. This roadmap outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. +The `GenerateDocumentationAction` class is a sophisticated component designed to automate the process of compiling documentation from code files within a project. This roadmap outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. ##### Phase 1: Core Functionality Enhancements @@ -1085,11 +1085,11 @@ The `DocumentationCompilerAction` class is a sophisticated component designed to ##### Conclusion -The development roadmap for `DocumentationCompilerAction` aims to create a powerful, user-friendly tool that simplifies the documentation process for developers. By focusing on core functionality enhancements, integration and compatibility, advanced features, and building a supportive community, the tool will become an indispensable part of the software development lifecycle. +The development roadmap for `GenerateDocumentationAction` aims to create a powerful, user-friendly tool that simplifies the documentation process for developers. By focusing on core functionality enhancements, integration and compatibility, advanced features, and building a supportive community, the tool will become an indispensable part of the software development lifecycle. -# kotlin\com\github\simiacryptus\aicoder\actions\generic\DictationAction.kt +# kotlin\com\github\simiacryptus\aicoder\actions\generic\VoiceToTextAction.kt -The `DictationAction` class is a sophisticated piece of software designed to integrate speech-to-text capabilities within an IDE, leveraging audio recording and processing to convert spoken words into text. This feature can significantly enhance productivity by allowing developers to dictate code comments, documentation, or even code itself. Below is a proposed feature development roadmap to enhance and expand the capabilities of the `DictationAction` class. +The `VoiceToTextAction` class is a sophisticated piece of software designed to integrate speech-to-text capabilities within an IDE, leveraging audio recording and processing to convert spoken words into text. This feature can significantly enhance productivity by allowing developers to dictate code comments, documentation, or even code itself. Below is a proposed feature development roadmap to enhance and expand the capabilities of the `VoiceToTextAction` class. #### Phase 1: Core Functionality and Stability @@ -1127,7 +1127,7 @@ The `DictationAction` class is a sophisticated piece of software designed to int - **6.2 Regular Updates**: Commit to regular updates, incorporating the latest advancements in speech-to-text technology and addressing emerging user needs. - **6.3 Community Engagement**: Engage with the developer community to share tips, gather use cases, and promote innovative uses of dictation in software development. -This roadmap outlines a comprehensive strategy for evolving the `DictationAction` class into a powerful tool that enhances productivity, fosters inclusivity, and revolutionizes the way developers interact with their IDE. +This roadmap outlines a comprehensive strategy for evolving the `VoiceToTextAction` class into a powerful tool that enhances productivity, fosters inclusivity, and revolutionizes the way developers interact with their IDE. # kotlin\com\github\simiacryptus\aicoder\actions\generic\DiffChatAction.kt @@ -1210,9 +1210,9 @@ The code provided outlines a Kotlin class `MarkdownListAction` that extends `Bas This roadmap provides a structured approach to developing the `MarkdownListAction` feature, focusing on enhancing functionality, usability, and integration, with an emphasis on user feedback and continuous improvement. -# kotlin\com\github\simiacryptus\aicoder\actions\generic\ReplaceOptionsAction.kt +# kotlin\com\github\simiacryptus\aicoder\actions\generic\ReplaceWithSuggestionsAction.kt -Creating a feature development roadmap for the `ReplaceOptionsAction` class and its associated functionalities involves outlining the stages of development, from initial setup to advanced features and potential future enhancements. This roadmap will guide the development process, ensuring a structured approach to adding features and improving the `ReplaceOptionsAction` class. +Creating a feature development roadmap for the `ReplaceWithSuggestionsAction` class and its associated functionalities involves outlining the stages of development, from initial setup to advanced features and potential future enhancements. This roadmap will guide the development process, ensuring a structured approach to adding features and improving the `ReplaceWithSuggestionsAction` class. #### Phase 1: Initial Setup and Core Functionality @@ -1244,7 +1244,7 @@ Creating a feature development roadmap for the `ReplaceOptionsAction` class and - **Machine Learning Model Training**: Investigate the possibility of training custom AI models based on user data and preferences, for more personalized and accurate suggestions. - **Community Contribution**: Open the development for community contributions, allowing other developers to add new features, support more languages, or improve existing functionalities. -This roadmap provides a structured approach to developing the `ReplaceOptionsAction` class, from basic functionality to advanced features and potential future enhancements. Each phase builds upon the previous one, gradually increasing the complexity and capabilities of the class, with a focus on usability, performance, and extensibility. +This roadmap provides a structured approach to developing the `ReplaceWithSuggestionsAction` class, from basic functionality to advanced features and potential future enhancements. Each phase builds upon the previous one, gradually increasing the complexity and capabilities of the class, with a focus on usability, performance, and extensibility. # kotlin\com\github\simiacryptus\aicoder\actions\SelectionAction.kt @@ -3910,9 +3910,9 @@ Creating a feature development roadmap for the `FileContextAction` class and its This roadmap is designed to be iterative, allowing for adjustments and new ideas to be incorporated as the project evolves. Each phase builds upon the previous ones, gradually enhancing the `FileContextAction` class to become more powerful, user-friendly, and integrated into the developers' workflow. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\AppendAction.kt +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\AppendTextWithChatAction.kt -The `AppendAction` class is a part of a larger project aimed at integrating AI capabilities into a development environment. This class specifically focuses on appending text to a user's selected text using an AI model. To further develop this feature and integrate more functionalities into the project, a feature development roadmap is proposed below. This roadmap outlines the progression from the current state to a more comprehensive and user-friendly AI integration. +The `AppendTextWithChatAction` class is a part of a larger project aimed at integrating AI capabilities into a development environment. This class specifically focuses on appending text to a user's selected text using an AI model. To further develop this feature and integrate more functionalities into the project, a feature development roadmap is proposed below. This roadmap outlines the progression from the current state to a more comprehensive and user-friendly AI integration. #### Phase 1: Core Functionality Enhancement @@ -3951,7 +3951,7 @@ The `AppendAction` class is a part of a larger project aimed at integrating AI c This roadmap is designed to be iterative, with each phase building upon the successes and lessons of the previous ones. Feedback from users and stakeholders will be crucial at every step to ensure that development aligns with user needs and expectations. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\AnalogueFileAction.kt +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\GenerateRelatedFileAction.kt The code provided is part of a larger project aimed at integrating AI-driven functionalities into an IDE, specifically for generating analogue files based on directives. The roadmap for developing and enhancing this feature can be structured into several phases, each focusing on different aspects of functionality, user experience, and integration. Below is a proposed feature development roadmap: @@ -3994,9 +3994,9 @@ The code provided is part of a larger project aimed at integrating AI-driven fun This roadmap is designed to be iterative, with each phase building upon the previous ones. It allows for flexibility to adapt to new developments in AI technology, user feedback, and changing requirements. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\DictationAction.kt +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\VoiceToTextAction.kt -The `DictationAction` class provides a comprehensive framework for integrating dictation capabilities into an application, leveraging audio recording, processing, and speech-to-text conversion. To further enhance and expand its functionality, a feature development roadmap is proposed. This roadmap outlines a series of planned improvements and new features, aimed at increasing the utility, performance, and user experience of the dictation feature. +The `VoiceToTextAction` class provides a comprehensive framework for integrating dictation capabilities into an application, leveraging audio recording, processing, and speech-to-text conversion. To further enhance and expand its functionality, a feature development roadmap is proposed. This roadmap outlines a series of planned improvements and new features, aimed at increasing the utility, performance, and user experience of the dictation feature. #### Phase 1: Core Improvements @@ -4117,9 +4117,9 @@ Creating a feature development roadmap involves outlining the stages of developm By following this roadmap, development teams can systematically approach feature development, ensuring that each stage is carefully planned and executed to deliver high-quality features that meet user needs and business objectives. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\CreateFileAction.kt +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\CreateFileFromDescriptionAction.kt -The code snippet provided is part of a larger project aimed at integrating natural language processing (NLP) capabilities into a development environment, specifically for generating files based on natural language directives. The `CreateFileAction` class is a key component of this system, leveraging an AI model to interpret directives and generate corresponding files within a project structure. To further develop and enhance this system, a feature development roadmap is proposed below, outlining potential improvements and expansions in a phased approach. +The code snippet provided is part of a larger project aimed at integrating natural language processing (NLP) capabilities into a development environment, specifically for generating files based on natural language directives. The `CreateFileFromDescriptionAction` class is a key component of this system, leveraging an AI model to interpret directives and generate corresponding files within a project structure. To further develop and enhance this system, a feature development roadmap is proposed below, outlining potential improvements and expansions in a phased approach. #### Phase 1: Core Functionality Enhancements @@ -4195,9 +4195,9 @@ The `DiffChatAction` class is a sophisticated component designed to enhance the #### Conclusion The development roadmap for the `DiffChatAction` class aims to transform it into a comprehensive tool that not only facilitates efficient code reviews and discussions but also integrates seamlessly into the developer's workflow, supports collaboration, and ensures high standards of code quality and security. By progressively implementing these features, the tool will become an essential component of the development ecosystem. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\ReplaceOptionsAction.kt +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\ReplaceWithSuggestionsAction.kt -The code snippet provided outlines a class `ReplaceOptionsAction` that extends `SelectionAction` and is designed to interact with a virtual API to suggest text replacements within a selected text in an IDE environment. This functionality is particularly useful for code editors and IDE plugins that aim to enhance developer productivity by automating code suggestions and replacements. Below is a feature development roadmap to further develop and enhance this functionality. +The code snippet provided outlines a class `ReplaceWithSuggestionsAction` that extends `SelectionAction` and is designed to interact with a virtual API to suggest text replacements within a selected text in an IDE environment. This functionality is particularly useful for code editors and IDE plugins that aim to enhance developer productivity by automating code suggestions and replacements. Below is a feature development roadmap to further develop and enhance this functionality. #### Phase 1: Core Functionality Enhancement @@ -4303,12 +4303,12 @@ Developing a feature, especially for a software project like an IntelliJ plugin, This roadmap is a guideline and may be adjusted based on project needs, unexpected challenges, or new opportunities that arise during development. Regular status meetings and updates will ensure the project stays on track and stakeholders are informed of progress. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\DocumentationCompilerAction.kt +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\GenerateDocumentationAction.kt -#### Feature Development Roadmap for DocumentationCompilerAction +#### Feature Development Roadmap for GenerateDocumentationAction -The `DocumentationCompilerAction` class is designed to automate the process of compiling documentation from code files within a project. This roadmap outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. +The `GenerateDocumentationAction` class is designed to automate the process of compiling documentation from code files within a project. This roadmap outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. ##### Phase 1: Core Functionality Enhancements @@ -4370,7 +4370,7 @@ The `DocumentationCompilerAction` class is designed to automate the process of c - Add support for Single Sign-On (SSO) and role-based access control for large teams and organizations. - Implement audit logs and compliance features for enterprise usage. -This roadmap is subject to change based on user feedback and technological advancements. The goal is to make `DocumentationCompilerAction` a comprehensive tool that simplifies the process of generating and maintaining high-quality documentation for software projects. +This roadmap is subject to change based on user feedback and technological advancements. The goal is to make `GenerateDocumentationAction` a comprehensive tool that simplifies the process of generating and maintaining high-quality documentation for software projects. # resources\sources\kt\com\github\simiacryptus\aicoder\ApplicationEvents.kt diff --git a/docs/manual_tests.md b/docs/manual_tests.md new file mode 100644 index 00000000..168768b9 --- /dev/null +++ b/docs/manual_tests.md @@ -0,0 +1,2642 @@ +# code\CustomEditAction.kt + + +#### Manual Test Plan for CustomEditAction Class + + +##### Objective: +To verify that the `CustomEditAction` class functions correctly, allowing users to edit code based on given instructions and configurations. + + +##### Test Environment: +- IDE: IntelliJ IDEA +- JDK version: Compatible version as per project requirements +- Dependencies: Ensure all project dependencies are resolved, including libraries for UI and OpenAI's ChatProxy. + + +##### Pre-requisites: +- The project should be correctly set up in IntelliJ IDEA. +- Ensure that `AppSettingsState` is properly configured with valid settings for `temperature`, `smartModel`, and `humanLanguage`. + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: To check if the basic functionality of editing code through virtual API is working. +**Steps**: +1. Open a project in IntelliJ. +2. Select a piece of code. +3. Trigger the `CustomEditAction`. +4. Enter a simple edit instruction, e.g., "Add a comment to this code". +5. Submit the instruction. +**Expected Result**: The code should be modified according to the instruction, with a comment added. + + +###### TC2: Input Validation Test +**Objective**: To verify that the action handles empty or null instructions properly. +**Steps**: +1. Trigger the `CustomEditAction` without selecting any code. +2. Enter an empty string or just press cancel in the input dialog. +**Expected Result**: No changes should be made to the code, and no errors should occur. + + +###### TC3: Language Compatibility Test +**Objective**: To verify that the action correctly handles different programming languages. +**Steps**: +1. Select a piece of code written in a non-Java language, e.g., Python. +2. Trigger the `CustomEditAction`. +3. Enter an instruction relevant to the selected language, e.g., "Format according to PEP8". +4. Submit the instruction. +**Expected Result**: The code should be modified according to the instruction and should be appropriate for the language. + + +###### TC4: Error Handling Test +**Objective**: To check how the action handles API failures or errors. +**Steps**: +1. Configure the `ChatProxy` to simulate an API failure. +2. Trigger the `CustomEditAction`. +3. Enter a valid instruction. +**Expected Result**: The user should be notified of the error, and no changes should be made to the code. + + +###### TC5: History Functionality Test +**Objective**: To verify that the instruction history is updated and used correctly. +**Steps**: +1. Trigger the `CustomEditAction` multiple times with different instructions. +2. Check if the recent instructions are stored and displayed correctly in subsequent uses. +**Expected Result**: The history should correctly reflect recent instructions, and users should be able to select from them. + + +###### TC6: Multi-language Support Test +**Objective**: To verify that the action supports editing code in different human languages. +**Steps**: +1. Change the `humanLanguage` setting in `AppSettingsState` to a non-English language. +2. Trigger the `CustomEditAction`. +3. Enter an instruction in the selected human language. +**Expected Result**: The code should be edited according to the instruction, and the interaction should be in the selected human language. + + +##### Post-Test Cleanup: +- Reset any changes made to the settings during testing. +- Close the project and IntelliJ IDEA. + + +##### Reporting: +- Document any discrepancies from the expected results. +- Capture screenshots or logs in case of failures. +- Provide feedback or suggestions for improving the functionality based on test results. + +This manual test plan will help ensure that the `CustomEditAction` class meets its functional requirements and handles different scenarios gracefully. + +# code\DocAction.kt + + +#### Manual Test Plan for `DocAction` Class + + +##### Objective: +To verify that the `DocAction` class correctly generates documentation comments for selected code blocks in supported programming languages. + + +##### Pre-requisites: +- IntelliJ IDEA or compatible IDE installed. +- Plugin containing the `DocAction` class is installed and enabled. +- Test projects in various supported languages (e.g., Java, Kotlin, Python) are set up. + + +##### Test Environment: +- Operating System: [Specify OS] +- IDE: IntelliJ IDEA [Specify version] +- Plugin Version: [Specify version] + + +##### Test Data: +- Various code snippets in supported languages. +- Configurations in `AppSettingsState`. + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: Ensure that `DocAction` generates appropriate documentation for a simple function. +- **Steps**: + 1. Open a project and navigate to a source file. + 2. Select a simple function or method. + 3. Trigger the `DocAction`. + 4. Observe the generated documentation. +- **Expected Result**: The documentation should be correctly added above the selected code block, matching the language's documentation style. + + +###### TC2: Language Support Verification +**Objective**: Verify that `DocAction` supports all specified languages and ignores unsupported ones. +- **Steps**: + 1. Repeat TC1 for each supported language (e.g., Java, Kotlin, Python). + 2. Attempt to use `DocAction` on an unsupported language (e.g., plain text). +- **Expected Result**: + - Documentation is generated for supported languages. + - An appropriate message or no action for unsupported languages. + + +###### TC3: Error Handling +**Objective**: Ensure that `DocAction` handles errors gracefully (e.g., API failures, invalid selections). +- **Steps**: + 1. Simulate API failure or provide invalid code selection. + 2. Trigger the `DocAction`. + 3. Observe the behavior and any error messages. +- **Expected Result**: The action should not crash the IDE and should display a user-friendly error message. + + +###### TC4: Configuration Impact +**Objective**: Test the impact of different configurations in `AppSettingsState` on the documentation generation. +- **Steps**: + 1. Modify settings in `AppSettingsState` (e.g., `humanLanguage`, `temperature`). + 2. Trigger the `DocAction` on a known code block. + 3. Observe and verify the changes in the generated documentation. +- **Expected Result**: Changes in settings should reflect appropriately in the documentation style and content. + + +###### TC5: Selection Boundary Test +**Objective**: Verify that `DocAction` correctly identifies the boundaries of code blocks. +- **Steps**: + 1. Select partial code blocks, nested functions, and adjacent code blocks. + 2. Trigger the `DocAction`. + 3. Check if the documentation is added correctly and only within the selected boundaries. +- **Expected Result**: Documentation should only apply within the exact boundaries of the selected code block. + + +###### TC6: Undo/Redo Functionality +**Objective**: Ensure that the documentation addition can be undone and redone without issues. +- **Steps**: + 1. Apply `DocAction` to a code block. + 2. Use the IDE's undo feature. + 3. Use the IDE's redo feature. +- **Expected Result**: + - The added documentation should be removed on undo. + - The removed documentation should be reinstated on redo. + + +##### Post-Test Cleanup: +- Revert any changes made to the test projects. +- Reset configurations in `AppSettingsState` to their original values. + + +##### Reporting: +- Document all test results, including any discrepancies from expected outcomes. +- Report any bugs or issues to the development team for resolution. + +This manual test plan will help ensure that the `DocAction` class functions correctly across different scenarios and configurations, providing reliable and accurate documentation generation in the IDE environment. + +# code\DescribeAction.kt + + +#### Manual Test Plan for `DescribeAction` Class + + +##### Objective: +To verify that the `DescribeAction` class correctly generates descriptions for selected code snippets in various programming languages and integrates these descriptions as comments in the appropriate format. + + +##### Pre-requisites: +- IntelliJ IDEA or a compatible IDE installed. +- Plugin containing the `DescribeAction` class is installed and enabled in the IDE. +- Access to the `ChatProxy` and `AppSettingsState` configurations. + + +##### Test Environment: +- Operating System: [Specify OS] +- IDE Version: [Specify IDE version] +- Plugin Version: [Specify Plugin version] + + +##### Test Data: +- Various code snippets in supported languages (e.g., Java, Python, JavaScript). +- Configurations in `AppSettingsState` for different languages and temperature settings. + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: Ensure that the `DescribeAction` can generate a basic description for a simple code snippet. +1. Open a project and create a file with a simple code snippet. +2. Select the code snippet. +3. Trigger the `DescribeAction`. +4. **Expected Result**: A comment is added above the selected code containing the description. + + +###### TC2: Language Support Test +**Objective**: Verify that the action handles different programming languages correctly. +1. Repeat TC1 for each supported programming language. +2. **Expected Result**: The descriptions are added in the correct comment style for each language. + + +###### TC3: Multi-line Comment Test +**Objective**: Check if multi-line comments are handled correctly when the description exceeds one line. +1. Select a code snippet that is expected to generate a multi-line description. +2. Trigger the `DescribeAction`. +3. **Expected Result**: The description should be enclosed in the appropriate multi-line comment format of the language. + + +###### TC4: Error Handling Test +**Objective**: Ensure that the action handles errors gracefully (e.g., network issues, API failures). +1. Simulate an API failure (e.g., by disconnecting from the network). +2. Trigger the `DescribeAction`. +3. **Expected Result**: An appropriate error message is displayed, and no changes are made to the code. + + +###### TC5: Configuration Change Impact Test +**Objective**: Verify that changes in `AppSettingsState` affect the output as expected. +1. Change the `humanLanguage` setting in `AppSettingsState`. +2. Trigger the `DescribeAction` on a code snippet. +3. **Expected Result**: The description should be in the newly set language. + + +###### TC6: Indentation and Formatting Test +**Objective**: Confirm that the action respects the original indentation and formatting of the code. +1. Select a code snippet with specific indentation. +2. Trigger the `DescribeAction`. +3. **Expected Result**: The description and the original code maintain their respective indentations. + + +###### TC7: Performance Test +**Objective**: Ensure that the action performs within acceptable time limits for large code snippets. +1. Select a large code snippet. +2. Trigger the `DescribeAction`. +3. **Expected Result**: The action completes within a reasonable time frame (e.g., a few seconds). + + +##### Post-Test Cleanup: +- Restore any settings changed during testing. +- Remove any test files or code snippets created. + + +##### Reporting: +- Document any discrepancies from the expected results. +- Capture screenshots or logs if applicable. +- Provide feedback or suggestions for improvement based on test results. + +This manual test plan will help ensure that the `DescribeAction` class functions correctly across various scenarios and configurations. + +# code\CommentsAction.kt + + +#### Manual Test Plan for `CommentsAction` Class + + +##### Objective: +To verify that the `CommentsAction` class functions correctly by adding comments to selected code based on the specified programming and human languages. + + +##### Pre-requisites: +- IntelliJ IDEA or similar IDE installed. +- Plugin containing the `CommentsAction` class is installed and enabled in the IDE. +- Access to the `ChatProxy` service configured correctly in the plugin settings. + + +##### Test Environment: +- Operating System: [Specify OS] +- IDE: IntelliJ IDEA [Specify version] +- Plugin Version: [Specify version] +- Network: Ensure stable internet connection for `ChatProxy` service interaction. + + +##### Test Data: +- Sample code snippets in supported programming languages (e.g., Java, Python, JavaScript). +- Ensure various programming languages include both simple and complex code structures. + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: Ensure that the `CommentsAction` can add comments to a simple piece of code. +1. Open a project in the IDE. +2. Insert a simple code snippet in a supported language. +3. Select the code snippet. +4. Trigger the `CommentsAction`. +5. **Expected Result**: Comments are added to each line of the code explaining the functionality. + + +###### TC2: Unsupported Language Test +**Objective**: Verify that the action does not process unsupported languages (e.g., plain text). +1. Open a project in the IDE. +2. Insert a plain text snippet. +3. Select the text. +4. Trigger the `CommentsAction`. +5. **Expected Result**: No action is taken, and possibly an informative message is displayed indicating unsupported language. + + +###### TC3: Null Selection Test +**Objective**: Ensure the action handles null or empty selections gracefully. +1. Open a project in the IDE. +2. Ensure no text is selected or a blank file is open. +3. Trigger the `CommentsAction`. +4. **Expected Result**: No processing occurs, and an error message may be displayed indicating no selection. + + +###### TC4: Network Failure Handling +**Objective**: Test how the action handles network failures during the `ChatProxy` call. +1. Open a project in the IDE. +2. Insert a valid code snippet. +3. Select the code snippet. +4. Simulate a network failure (disconnect from the internet). +5. Trigger the `CommentsAction`. +6. **Expected Result**: The action should handle the failure gracefully, possibly with an error notification about network issues. + + +###### TC5: Multiple Languages and Complex Code +**Objective**: Verify that the action can handle complex code snippets across different supported languages. +1. Open a project in the IDE. +2. Insert complex code snippets in different supported languages (e.g., nested loops, multiple functions). +3. Select each snippet one by one and trigger the `CommentsAction`. +4. **Expected Result**: Comments should accurately describe complex code structures in the appropriate human language. + + +###### TC6: Configuration and Settings Test +**Objective**: Ensure that changes in settings (temperature, model) affect the output. +1. Open settings in the IDE where `AppSettingsState` is configurable. +2. Change the `temperature` and `model` settings. +3. Insert a code snippet and select it. +4. Trigger the `CommentsAction`. +5. **Expected Result**: The output should reflect the changes in configuration, potentially altering the style or detail of comments. + + +##### Post-Test Cleanup: +- Restore any settings changed during testing. +- Remove any test code snippets or files created during the test. + + +##### Reporting: +- Document all outcomes and, if any test fails, capture screenshots or logs if applicable. +- Report the findings to the development team for further action or bug fixing. + +This manual test plan will help ensure that the `CommentsAction` class performs as expected across various scenarios and handles errors gracefully. + +# code\ImplementStubAction.kt + + +#### Manual Test Plan for `ImplementStubAction` Class + + +##### Objective: +To manually test the `ImplementStubAction` class to ensure it correctly interacts with the `VirtualAPI` to edit code stubs based on user selections within an IDE environment. + + +##### Test Environment: +- IDE (e.g., IntelliJ IDEA) +- Java SDK installed +- Plugin containing the `ImplementStubAction` class installed in the IDE +- Access to the backend services (e.g., `ChatProxy` and `VirtualAPI`) + + +##### Pre-requisites: +- The plugin is correctly installed and enabled in the IDE. +- The backend services are operational and accessible. + + +##### Test Cases: + + +###### TC1: Language Support Validation +**Objective**: Verify that the `isLanguageSupported` method correctly identifies supported and unsupported languages. +1. **Steps**: + - Invoke the method with various `ComputerLanguage` values including `null`, `ComputerLanguage.Text`, and other supported languages. +2. **Expected Results**: + - The method should return `false` for `null` and `ComputerLanguage.Text`. + - The method should return `true` for other supported languages. + + +###### TC2: Default Selection for Code +**Objective**: Ensure that the `defaultSelection` method correctly identifies the smallest code block or the entire line if no code blocks are identified. +1. **Steps**: + - Provide an `EditorState` with multiple code ranges and invoke the method. + - Provide an `EditorState` without code ranges and invoke the method. +2. **Expected Results**: + - Returns the range of the smallest code block when available. + - Returns the entire line if no code blocks are present. + + +###### TC3: Code Editing via Virtual API +**Objective**: Test the `processSelection` method's ability to send code to the `VirtualAPI` and receive edited code. +1. **Steps**: + - Select a stub code in the editor. + - Trigger the `processSelection` method. +2. **Expected Results**: + - The method sends the correct parameters to the `VirtualAPI`. + - The method updates the editor with the returned `ConvertedText.code`. + + +###### TC4: Error Handling and Stability +**Objective**: Ensure the action handles errors gracefully when the backend service is unavailable or returns an error. +1. **Steps**: + - Simulate backend service failure or error responses. + - Trigger the `processSelection` method. +2. **Expected Results**: + - The method should not crash the IDE. + - Appropriate error messages or logs should be generated. + + +###### TC5: User Interface and Integration +**Objective**: Confirm that the action integrates well with the IDE and user interactions are handled smoothly. +1. **Steps**: + - Use the IDE's interface to trigger the action through context menus or keyboard shortcuts. + - Observe the interaction and any UI changes or prompts. +2. **Expected Results**: + - The action should be accessible through the expected UI elements. + - Any dialogs or prompts should display correctly and be user-friendly. + + +##### Post-Test Cleanup: +- Reset any configurations or settings changed during testing. +- Ensure no residual data or state from testing affects the normal operation of the IDE or plugin. + + +##### Reporting: +- Document all test results, noting any failures or unexpected behaviors. +- Report bugs or issues to the development team for resolution. + +This manual test plan will help ensure that the `ImplementStubAction` class functions correctly within its intended environment and interacts properly with external services. + +# code\InsertImplementationAction.kt + + +#### Manual Test Plan for `InsertImplementationAction` Class + + +##### Objective: +To ensure that the `InsertImplementationAction` class functions correctly across various scenarios, including handling different programming languages, processing comments, and interacting with the virtual API to generate code implementations. + + +##### Test Environment: +- IDE with support for the plugin (e.g., IntelliJ IDEA). +- Access to the `AppSettingsState` configurations. +- A project with source code in supported languages. + + +##### Prerequisites: +- Plugin is installed and enabled in the IDE. +- `AppSettingsState` is configured with valid settings for `smartModel`, `chatModel`, and `temperature`. + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: Verify that the action correctly inserts generated code based on a single line comment. +1. Open a source file in a supported language. +2. Select a single line comment that specifies a clear implementation requirement. +3. Trigger the `InsertImplementationAction`. +4. **Expected Result**: + - The action communicates with the virtual API. + - Generated code is inserted correctly below the comment. + + +###### TC2: Multi-line Comment Test +**Objective**: Verify that the action handles multi-line comments correctly. +1. Open a source file in a supported language. +2. Select a multi-line comment with a detailed specification. +3. Trigger the `InsertImplementationAction`. +4. **Expected Result**: + - The action processes the entire comment as a single specification. + - Appropriate code is generated and inserted. + + +###### TC3: No Comment Selected Test +**Objective**: Verify behavior when no comment is selected. +1. Open a source file in a supported language. +2. Place the cursor in a code block without any nearby comments. +3. Trigger the `InsertImplementationAction`. +4. **Expected Result**: + - No action is taken, or a user-friendly message is displayed indicating no specification found. + + +###### TC4: Unsupported Language Test +**Objective**: Verify that the action does not proceed with unsupported languages. +1. Open a source file in an unsupported language (e.g., plain text or Markdown). +2. Select any portion of text. +3. Trigger the `InsertImplementationAction`. +4. **Expected Result**: + - The action should not proceed. + - A message indicates that the language is not supported. + + +###### TC5: Error Handling Test +**Objective**: Verify that the action handles API errors gracefully. +1. Configure the `AppSettingsState` with an invalid `chatModel`. +2. Open a source file in a supported language. +3. Select a comment and trigger the `InsertImplementationAction`. +4. **Expected Result**: + - The action should handle the error without crashing. + - A user-friendly error message is displayed. + + +###### TC6: Large Specification Test +**Objective**: Verify that the action handles large specifications without performance degradation. +1. Open a source file in a supported language. +2. Select a very long comment that spans multiple lines and includes complex specifications. +3. Trigger the `InsertImplementationAction`. +4. **Expected Result**: + - The action processes the comment efficiently. + - Code is generated and inserted without significant delay. + + +##### Reporting: +- Document the outcome of each test case. +- Capture any discrepancies from the expected results. +- Report bugs or enhancements to the development team. + + +##### Cleanup: +- Revert any changes made to the source files during testing. +- Restore original `AppSettingsState` configurations if modified. + +This manual test plan will help ensure that the `InsertImplementationAction` class meets its functional requirements and handles edge cases gracefully. + +# code\PasteAction.kt + + +#### Manual Test Plan for `PasteAction` Class + + +##### Objective: +To verify that the `PasteAction` class functions correctly by pasting and converting clipboard content into a specified programming language using a virtual API. + + +##### Prerequisites: +- IntelliJ IDEA or a similar IDE installed. +- Plugin containing the `PasteAction` class is installed and enabled. +- Clipboard operations are permitted on the test machine. + + +##### Test Environment: +- Operating System: [Specify OS] +- IDE: IntelliJ IDEA [Specify version] +- Java Version: [Specify version] +- Dependencies: Ensure all dependencies are correctly configured, including `ChatProxy` and `VirtualAPI`. + + +##### Test Data: +- Various strings representing code snippets in different languages. +- Non-code text to test language detection and rejection. + + +##### Test Cases: + + +###### TC1: Clipboard Contains Valid Code Snippet +**Objective**: Verify that the action correctly pastes and converts a valid code snippet from the clipboard. +1. Copy a valid code snippet (e.g., Java code) to the clipboard. +2. Trigger the `PasteAction`. +3. Verify that the output is the expected converted code in the target language specified in the `SelectionState`. + + +###### TC2: Clipboard Contains Plain Text +**Objective**: Verify that the action handles plain text (non-code) appropriately. +1. Copy plain text (e.g., "Hello World") to the clipboard. +2. Trigger the `PasteAction`. +3. Verify that the action either converts the text or handles it as unsupported, based on implementation. + + +###### TC3: Unsupported Language Conversion +**Objective**: Verify that the action handles conversion requests for unsupported languages. +1. Set the target language in `SelectionState` to an unsupported language. +2. Copy a valid code snippet to the clipboard. +3. Trigger the `PasteAction`. +4. Verify that the action handles the unsupported language gracefully (e.g., error message, no conversion). + + +###### TC4: Clipboard is Empty +**Objective**: Verify that the action handles an empty clipboard correctly. +1. Ensure the clipboard is empty. +2. Trigger the `PasteAction`. +3. Verify that the action does not proceed with conversion and handles the situation appropriately. + + +###### TC5: Error Handling in API +**Objective**: Verify that the action handles API errors gracefully. +1. Simulate an API failure (e.g., network error, API returns error). +2. Copy a valid code snippet to the clipboard. +3. Trigger the `PasteAction`. +4. Verify that the action handles the error gracefully and provides a user-friendly message. + + +###### TC6: Check Language Support +**Objective**: Verify that the action correctly identifies supported and unsupported languages. +1. Iterate through a list of known supported and unsupported languages. +2. For each language, set it in `SelectionState` and copy a corresponding code snippet to the clipboard. +3. Trigger the `PasteAction`. +4. Verify that the action correctly identifies whether the language is supported. + + +##### Reporting: +- Document the results of each test case. +- Include details such as the input, expected outcome, actual outcome, and any discrepancies. +- Report any bugs or issues to the development team for resolution. + + +##### Cleanup: +- Reset any settings or configurations changed during testing. +- Clear the clipboard to avoid any data leakage. + +This manual test plan will help ensure that the `PasteAction` class behaves as expected under various conditions and handles different types of clipboard content appropriately. + +# code\RecentCodeEditsAction.kt + + +#### Manual Test Plan for RecentCodeEditsAction Class + + +##### Objective: +To ensure that the `RecentCodeEditsAction` class functions correctly, providing a dynamic list of recent custom code edits in the IDE, and enabling or disabling based on the context. + + +##### Pre-requisites: +- IntelliJ IDEA or compatible IDE installed. +- Plugin containing the `RecentCodeEditsAction` class installed and enabled. +- `AppSettingsState` configured with a mock or real data source for recent commands. + + +##### Test Environment: +- Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur] +- IDE Version: [Specify version - e.g., IntelliJ IDEA 2021.3] +- Java Version: [Specify version - e.g., Java 11] + + +##### Test Data: +- Sample recent commands in `AppSettingsState`: + - "Refactor variable names" + - "Optimize imports" + - "Format code" + - "Add documentation comments" + + +##### Test Cases: + + +###### TC1: Visibility and Enablement of Action +**Objective**: Verify that the action is visible and enabled only when appropriate. +**Steps**: +1. Open a project in the IDE. +2. Select a text file and right-click to open the context menu. +3. Observe if the `RecentCodeEditsAction` is visible and enabled. +4. Repeat steps 2-3 with a source code file (e.g., a Java file). + +**Expected Results**: +- The action should be invisible and disabled for text files. +- The action should be visible and enabled for source code files. + + +###### TC2: Correct Listing of Recent Edits +**Objective**: Verify that the action correctly lists recent code edits. +**Steps**: +1. Trigger the `RecentCodeEditsAction` by selecting it from the context menu in a source code file. +2. Observe the list of actions displayed. + +**Expected Results**: +- The list should correctly display all recent edits stored in `AppSettingsState`, formatted as specified (e.g., "_1: Refactor variable names"). + + +###### TC3: Execution of a Recent Edit Command +**Objective**: Verify that selecting a recent edit command executes it correctly. +**Steps**: +1. From the list of recent edits, select an action (e.g., "_1: Refactor variable names"). +2. Observe the behavior in the IDE (you may need to simulate or mock the execution effect). + +**Expected Results**: +- The selected action should execute appropriately (e.g., refactoring process starts). + + +###### TC4: Dynamic Update of Recent Edits List +**Objective**: Verify that the list updates dynamically with new edits. +**Steps**: +1. Add a new edit command to `AppSettingsState`. +2. Reopen or refresh the `RecentCodeEditsAction` list. +3. Check if the new command appears in the list. + +**Expected Results**: +- The new command should appear in the list without requiring a restart of the IDE. + + +##### Post-Test Cleanup: +- Reset any changes made to `AppSettingsState` or other configurations during testing. + + +##### Reporting: +- Document any discrepancies from expected results. +- Capture screenshots or logs if applicable. +- Provide feedback or suggestions for improvements based on test outcomes. + +This manual test plan aims to cover basic functional aspects of the `RecentCodeEditsAction` class. Adjustments may be necessary based on actual application behavior and additional requirements. + +# code\RenameVariablesAction.kt + + +#### Manual Test Plan for `RenameVariablesAction` Class + + +##### Objective +To manually test the `RenameVariablesAction` class to ensure that it correctly suggests and applies variable name changes in code based on AI recommendations. + + +##### Test Environment +- IDE: IntelliJ IDEA +- Project setup with necessary dependencies and plugin configurations. +- Access to `AppSettingsState` and `ChatProxy` configurations. + + +##### Pre-requisites +- The plugin containing `RenameVariablesAction` is installed and enabled in IntelliJ IDEA. +- The user has opened a project with source code files in supported languages. + + +##### Test Cases + + +###### TC1: Basic Functionality Test +**Objective**: Verify that the action suggests and applies renames correctly for a simple case. +1. **Steps**: + - Open a source file with a few variables. + - Highlight a variable name. + - Trigger the `RenameVariablesAction`. + - Select all suggested renames in the dialog. + - Apply the changes. +2. **Expected Result**: + - The variable names in the code are renamed as suggested by the AI. + - No syntax errors or unresolved references should occur due to renaming. + + +###### TC2: No Selection Test +**Objective**: Verify the behavior when no text is selected. +1. **Steps**: + - Open a source file. + - Ensure no text is selected. + - Trigger the `RenameVariablesAction`. +2. **Expected Result**: + - An appropriate message indicating no selection or no operation should be displayed. + + +###### TC3: Unsupported Language Test +**Objective**: Verify that the action does not proceed in unsupported languages. +1. **Steps**: + - Open a text file or a file of an unsupported language. + - Select some text. + - Trigger the `RenameVariablesAction`. +2. **Expected Result**: + - The action should not proceed, possibly showing a message that the language is unsupported. + + +###### TC4: Multiple Suggestions Test +**Objective**: Verify that the action handles multiple suggestions correctly. +1. **Steps**: + - Open a source file with multiple variables. + - Highlight a block of code containing multiple variable names. + - Trigger the `RenameVariablesAction`. + - Choose only a subset of the suggested renames. + - Apply the changes. +2. **Expected Result**: + - Only the selected variable names should be renamed. + - The code should remain functional with no unresolved references. + + +###### TC5: Cancel Operation Test +**Objective**: Verify that cancelling the rename operation leaves the code unchanged. +1. **Steps**: + - Open a source file. + - Select a variable name. + - Trigger the `RenameVariablesAction`. + - When the rename suggestions dialog appears, cancel the operation. +2. **Expected Result**: + - No changes should be made to the code. + + +###### TC6: Error Handling Test +**Objective**: Verify that the system handles errors gracefully (e.g., API failures, network issues). +1. **Steps**: + - Simulate an API failure or network issue (e.g., by temporarily modifying the `ChatProxy` settings to an invalid state). + - Open a source file and select a variable name. + - Trigger the `RenameVariablesAction`. +2. **Expected Result**: + - An error message should be displayed, and no changes should be made to the code. + + +##### Post-Test Cleanup +- Restore any settings or configurations changed during testing. +- Close all open files and projects in the IDE. + + +##### Reporting +- Document the results of each test case, including any discrepancies from expected outcomes. +- Report any bugs or issues to the development team for resolution. + +# dev\AppServer.kt + + +#### Manual Test Plan for AppServer Class + + +##### Objective: +To verify the functionality and robustness of the `AppServer` class, ensuring it can handle web application contexts, manage WebSocket connections, and respond appropriately to user interactions and system events. + + +##### Test Environment: +- IDE: IntelliJ IDEA +- JDK version: Java 11 or higher +- Operating System: Windows/Linux/MacOS +- Required Libraries: Jetty server, SLF4J, WebSocket API + + +##### Test Data: +- Local server name: "localhost" +- Port: 8080 +- Sample paths for web applications: "/chat", "/info" +- Sample `ChatServer` instances + + +##### Pre-conditions: +- Ensure that the required Java version and libraries are installed and configured. +- Ensure no other services are running on the test port (8080). + + +##### Test Cases: + +1. **Initialization Test** + - **Objective**: Verify that the server initializes correctly with the specified local name and port. + - **Steps**: + 1. Instantiate `AppServer` with "localhost" and 8080. + 2. Call `start()` method. + - **Expected Result**: Server starts without errors, and logs indicate initialization at the specified address and port. + +2. **Add Application Test** + - **Objective**: Verify that applications can be added dynamically and are accessible. + - **Steps**: + 1. Start the server. + 2. Create a `ChatServer` instance and add it using `addApp("/chat", chatServerInstance)`. + 3. Access `localhost:8080/chat`. + - **Expected Result**: + - The server should restart with the new context. + - The chat application should be accessible and functional at the specified path. + +3. **Server Restart on New App Addition** + - **Objective**: Ensure the server restarts correctly when a new application is added. + - **Steps**: + 1. Start the server. + 2. Add a new `ChatServer` application. + 3. Monitor logs for restart messages. + - **Expected Result**: Logs should indicate that the server was stopped and restarted successfully. + +4. **Concurrency Test** + - **Objective**: Verify that the server can handle multiple requests simultaneously. + - **Steps**: + 1. Start the server. + 2. Simultaneously access multiple paths ("/chat", "/info") from different clients. + - **Expected Result**: All clients should receive correct responses without any delay or errors. + +5. **Error Handling Test** + - **Objective**: Verify that the server handles errors gracefully. + - **Steps**: + 1. Start the server. + 2. Simulate an error scenario (e.g., add an app with invalid configuration). + 3. Check the response and logs. + - **Expected Result**: Appropriate error messages are logged, and the server continues to run other contexts correctly. + +6. **Server Stop Test** + - **Objective**: Ensure the server stops cleanly on command. + - **Steps**: + 1. Start the server. + 2. Call `stop()` from the `AppServer.Companion` object. + - **Expected Result**: Server stops without errors, and logs indicate a clean shutdown. + +7. **Resource Leak Test** + - **Objective**: Ensure there are no resource leaks (threads, file handles, sockets) after server operations. + - **Steps**: + 1. Start and stop the server multiple times. + 2. Monitor system resources. + - **Expected Result**: No increase in resource usage over time, indicating no leaks. + + +##### Post-conditions: +- Server should be stopped, and all resources should be released. + + +##### Reporting: +- Document all test results, including any discrepancies from expected outcomes. +- Log all error messages and stack traces for failed tests. + + +##### Cleanup: +- Ensure all instances of `AppServer` are terminated. +- Release any ports and system resources used during testing. + +This manual test plan will help ensure that the `AppServer` class functions as expected under various conditions and handles errors and multiple simultaneous requests efficiently. + +# dev\PrintTreeAction.kt + + +#### Manual Test Plan for PrintTreeAction + + +##### Objective: +To verify that the `PrintTreeAction` in the IntelliJ plugin correctly prints the tree structure of a PsiFile when triggered. + + +##### Pre-requisites: +1. IntelliJ IDEA must be installed. +2. The plugin containing `PrintTreeAction` must be installed and enabled in IntelliJ IDEA. +3. `devActions` setting must be enabled in the plugin's `AppSettingsState`. + + +##### Test Environment: +- Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur, etc.] +- IntelliJ IDEA Version: [Specify version - e.g., 2021.2] +- Plugin Version: [Specify version] + + +##### Test Data: +- Various PsiFiles with different complexities and structures. + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: Ensure that the action prints the tree structure for a simple PsiFile. +**Steps**: +1. Open a simple project in IntelliJ. +2. Open a file (e.g., a simple Java class). +3. Right-click in the editor window and select "PrintTreeAction" from the context menu. +**Expected Result**: +- The tree structure of the PsiFile is printed in the log. + + +###### TC2: Action Visibility Test +**Objective**: Verify that the action is only visible when `devActions` is enabled. +**Steps**: +1. Disable `devActions` in the plugin settings. +2. Right-click in the editor window. +**Expected Result**: +- The "PrintTreeAction" should not be visible in the context menu. + + +###### TC3: Action Enabled Test with `devActions` Enabled +**Objective**: Confirm that the action is enabled when `devActions` is true. +**Steps**: +1. Ensure `devActions` is enabled. +2. Right-click in the editor window and observe the "PrintTreeAction". +**Expected Result**: +- The action should be enabled and selectable. + + +###### TC4: Large File Test +**Objective**: Test the action's performance and correctness on a large PsiFile. +**Steps**: +1. Open a large file (e.g., a file with thousands of lines of code). +2. Trigger the "PrintTreeAction". +**Expected Result**: +- The tree structure is printed in the log without crashing or significant performance degradation. + + +###### TC5: Error Handling Test +**Objective**: Ensure the action handles null PsiFile gracefully. +**Steps**: +1. Open an empty editor window (no file open). +2. Try to trigger the "PrintTreeAction". +**Expected Result**: +- An appropriate error message is logged, indicating no file is open or the file is not valid. + + +###### TC6: Logging Verification Test +**Objective**: Verify that the output is logged correctly. +**Steps**: +1. Trigger the action with any open file. +2. Check the IntelliJ log for the output. +**Expected Result**: +- The output in the log matches the expected tree structure of the PsiFile. + + +##### Post-Test Cleanup: +- Reset any settings changed during testing. +- Close any files or projects opened during testing. + + +##### Reporting: +- Document any discrepancies from the expected results. +- Capture log outputs and any error messages for failed test cases. +- Provide feedback or suggestions for improving the action based on test results. + +This manual test plan will help ensure that the `PrintTreeAction` functions correctly across different scenarios and setups, providing confidence in its reliability and effectiveness. + +# generic\GenerateRelatedFileAction.kt + + +#### Manual Test Plan for CreateFileFromTemplateAction Class + + +##### Objective: +To verify that the `CreateFileFromTemplateAction` class functions correctly across various scenarios, including file generation based on user directives and handling of file paths. + + +##### Test Environment Setup: +- Install IntelliJ IDEA or compatible IDE. +- Ensure the plugin containing `CreateFileFromTemplateAction` is installed and enabled. +- Configure necessary dependencies and environment as per the project requirements. + + +##### Test Data: +- Various project files with different content and structures. +- Directives for file generation (e.g., "Create test cases", "Refactor code to new standards"). + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: Verify that the action generates a new file correctly based on a simple directive. +1. **Preconditions**: Open a project with at least one non-directory file. +2. **Test Steps**: + - Right-click on a file and select "Create Analogue File". + - Enter the directive: "Create test cases". + - Execute the action. +3. **Expected Results**: + - A new file is created in the same directory as the original. + - The new file contains content relevant to the directive. + + +###### TC2: Directory Selection Handling +**Objective**: Ensure the action is disabled when a directory is selected. +1. **Preconditions**: Open a project and select a directory. +2. **Test Steps**: + - Right-click on the directory and observe the available actions. +3. **Expected Results**: + - The "Create Analogue File" action should be disabled or not visible. + + +###### TC3: Non-existent Path Handling +**Objective**: Verify the action's response when the generated file path does not exist. +1. **Preconditions**: Open a project with at least one file. +2. **Test Steps**: + - Right-click on a file and select "Create Analogue File". + - Enter a directive that implies saving to a non-existent path. + - Execute the action. +3. **Expected Results**: + - Directories along the path are created as needed. + - The file is successfully created at the specified path. + + +###### TC4: File Overwrite Handling +**Objective**: Test how the action handles scenarios where the file already exists. +1. **Preconditions**: A file already exists at the target path. +2. **Test Steps**: + - Right-click on a file and select "Create Analogue File". + - Enter a directive that results in a file path where a file already exists. + - Execute the action. +3. **Expected Results**: + - The action does not overwrite the existing file but creates a new file with a modified name to avoid duplication. + + +###### TC5: Error Handling and Messages +**Objective**: Ensure that appropriate error messages are displayed for various failure scenarios. +1. **Preconditions**: Open a project. +2. **Test Steps**: + - Induce different error scenarios like API failures, permission issues, etc. + - Observe the error handling and messages displayed. +3. **Expected Results**: + - Relevant and user-friendly error messages are displayed. + - The system handles exceptions gracefully without crashing. + + +###### TC6: Performance Test +**Objective**: Verify that the action performs well even with large files or under load. +1. **Preconditions**: Open a project with large files. +2. **Test Steps**: + - Execute the action on large files multiple times. + - Monitor the response time and resource usage. +3. **Expected Results**: + - The action completes within a reasonable time. + - No significant degradation in IDE performance. + + +##### Post-Test Cleanup: +- Remove any files or configurations added specifically for testing. +- Restore any settings changed during the test. + + +##### Reporting: +- Document all test results, including any discrepancies from expected outcomes. +- Report bugs or enhancement requests based on the findings. + +This manual test plan ensures comprehensive coverage of the `CreateFileFromTemplateAction` functionality and helps maintain high quality and reliability of the feature. + +# generic\AppendTextWithChatAction.kt + + +#### Manual Test Plan for `AppendTextWithChatAction` Class + + +##### Objective: +To verify that the `AppendTextWithChatAction` class correctly appends text to the user's selected text using the AI model's response. + + +##### Pre-requisites: +- IntelliJ IDEA or any compatible IDE installed. +- Access to the project's repository and necessary permissions to run and test the code. +- Ensure the AI model and API are properly configured and accessible. + + +##### Test Environment: +- Development or testing environment with the project setup. +- Ensure all dependencies are correctly configured in the project. + + +##### Test Data: +- Various strings of text to use as user selections. +- Configurations in `AppSettingsState` for different scenarios (e.g., different temperatures, models). + + +##### Test Cases: + + +###### TC1: Basic Append Functionality +**Objective**: To test if the system appends any text to the selected text. +**Steps**: +1. Open a file in the IDE and select a string of text. +2. Trigger the `AppendTextWithChatAction`. +3. Observe the output in the IDE or the designated output area. +**Expected Result**: The selected text should have additional text appended at the end. + + +###### TC2: No Selected Text +**Objective**: To verify the behavior when no text is selected. +**Steps**: +1. Ensure no text is selected in the IDE. +2. Trigger the `AppendTextWithChatAction`. +3. Observe the output or any error messages. +**Expected Result**: No changes should occur, or a user-friendly message should be displayed. + + +###### TC3: API Response Handling +**Objective**: To test the handling of different API responses, including errors. +**Steps**: +1. Mock different responses from the API, including success, failure, and edge cases like empty strings or null. +2. Select a string of text and trigger the `AppendTextWithChatAction` for each mocked response. +3. Observe how the application handles each response. +**Expected Result**: The application should handle each scenario gracefully, appending text correctly on success, and showing appropriate messages or handling on failures. + + +###### TC4: Long Text Selections +**Objective**: To test the system's performance with very long text selections. +**Steps**: +1. Select a very long string of text in the IDE. +2. Trigger the `AppendTextWithChatAction`. +3. Observe the performance and any potential lag or failure. +**Expected Result**: The action should complete within a reasonable time without errors. + + +###### TC5: Special Characters and Formats +**Objective**: To verify that the action handles text with special characters and formats correctly. +**Steps**: +1. Select text containing special characters (e.g., emojis, symbols) or formats (e.g., code snippets, markdown). +2. Trigger the `AppendTextWithChatAction`. +3. Check if the appended text respects the original format and characters. +**Expected Result**: The appended text should correctly include and display special characters and formats. + + +###### TC6: Configuration Changes +**Objective**: To test the system's response to changes in configuration settings. +**Steps**: +1. Change the settings in `AppSettingsState` (e.g., different AI models, temperature settings). +2. Select a string of text and trigger the `AppendTextWithChatAction`. +3. Observe how the changes affect the output. +**Expected Result**: Outputs should vary according to the configuration, reflecting the changes accurately. + + +##### Post-Test Cleanup: +- Reset any configurations changed during testing to their original states. +- Close and clean up any resources used during the test. + + +##### Reporting: +- Document any discrepancies from the expected results. +- Provide feedback and suggestions based on the test outcomes. + +This manual test plan will help ensure that the `AppendTextWithChatAction` class functions correctly across various scenarios and handles both expected and edge cases gracefully. + +# generic\CodeChatAction.kt + + +#### Manual Test Plan for CodeChatAction + + +##### Objective: +To manually test the `CodeChatAction` class to ensure it correctly initializes and handles a code chat session within an IDE environment. + + +##### Pre-requisites: +1. IntelliJ IDEA or a similar IDE installed. +2. Plugin containing the `CodeChatAction` class installed in the IDE. +3. Necessary permissions to access and modify files and to open web browsers from the IDE. + + +##### Test Environment: +- Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur] +- IDE Version: [Specify IDE version] +- Plugin Version: [Specify plugin version] +- Network Configuration: Ensure internet access for server communication. + + +##### Test Data: +- Sample code files in various supported languages (e.g., Java, Python, C++). + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: Verify that the action is triggered correctly and opens a chat session in the default browser. +1. Open a project and select a file. +2. Trigger the `CodeChatAction`. +3. **Expected Result**: + - A new browser tab opens with the chat interface. + - The chat session corresponds to the selected file and language. + + +###### TC2: Null Editor Handling +**Objective**: Ensure the action handles null editor instances gracefully. +1. Trigger the `CodeChatAction` without opening any file. +2. **Expected Result**: + - No action is taken. + - No errors or crashes occur. + + +###### TC3: Unsupported Language Handling +**Objective**: Verify that the action handles files with unsupported languages gracefully. +1. Open a file with an unsupported language or plain text. +2. Trigger the `CodeChatAction`. +3. **Expected Result**: + - No chat session is initiated. + - Appropriate user feedback is provided (e.g., a notification). + + +###### TC4: Session Initialization +**Objective**: Check if a new session is correctly initialized with valid parameters. +1. Open a supported file and select some text. +2. Trigger the `CodeChatAction`. +3. **Expected Result**: + - A new session is created with the correct language and selected text. + - The session ID is correctly appended to the URL. + + +###### TC5: Error Handling in Browser Opening +**Objective**: Ensure that errors during browser opening are logged without crashing the application. +1. Temporarily modify system settings to prevent the IDE from opening a browser. +2. Trigger the `CodeChatAction`. +3. **Expected Result**: + - An error is logged. + - The application does not crash. + + +###### TC6: Multiple Sessions Handling +**Objective**: Verify that multiple sessions can be handled simultaneously without interference. +1. Open multiple files in different tabs. +2. Trigger the `CodeChatAction` in each tab sequentially. +3. **Expected Result**: + - Each file opens its own chat session in a new browser tab. + - Sessions do not interfere with each other. + + +##### Post-Test Cleanup: +- Close all opened browser tabs and IDE projects. +- Restore any modified system settings. + + +##### Reporting: +- Document all outcomes and any deviations from expected results. +- Capture logs and screenshots for failed test cases. +- Provide recommendations for bug fixes or enhancements based on test outcomes. + +This manual test plan will help ensure that the `CodeChatAction` behaves as expected across various scenarios and handles edge cases gracefully. + +# generic\VoiceToTextAction.kt + + +#### Manual Test Plan for VoiceToTextAction Class + + +##### Objective: +To ensure that the `VoiceToTextAction` class functions correctly, handling audio input, processing it, and converting it into text which is then inserted into the editor at the correct position. + + +##### Test Environment: +- IDE with the plugin installed (e.g., IntelliJ IDEA). +- Operating system with audio input capabilities. +- Microphone setup and configured. + + +##### Prerequisites: +- Plugin is installed and enabled in the IDE. +- Microphone is connected and set as the default recording device. + + +##### Test Cases: + + +###### TC1: Basic Dictation Functionality +**Objective**: Verify that the dictation starts, processes audio, and the text is inserted into the editor. +1. Open a project and a file in the IDE. +2. Place the cursor in the editor where the text should be inserted. +3. Trigger the `VoiceToTextAction`. +4. Speak a few sentences into the microphone. +5. Verify that: + - The recording starts and the status dialog appears. + - The audio is processed, and the speech-to-text conversion happens. + - The text appears in the editor at the cursor's position. +6. Close the status dialog to stop the recording. +7. Check the final text in the editor for accuracy. + + +###### TC2: Dictation with Selected Text +**Objective**: Ensure that dictation handles initial prompts from selected text correctly. +1. Open a project and a file in the IDE. +2. Select a portion of text in the editor. +3. Trigger the `VoiceToTextAction`. +4. Speak a continuation of the selected text. +5. Verify that: + - The selected text is used as a prompt. + - The dictated text follows the selected text logically and grammatically. +6. Close the status dialog to end the session. +7. Review the text for logical continuation and correctness. + + +###### TC3: Error Handling +**Objective**: Test the error handling when an exception occurs during recording or processing. +1. Open a project and a file in the IDE. +2. Trigger the `VoiceToTextAction`. +3. During recording, simulate an error (e.g., disconnect the microphone). +4. Verify that: + - An error message is displayed. + - The process stops gracefully without crashing the IDE. +5. Reconnect the microphone and restart the dictation to check recovery. + + +###### TC4: Concurrency and Performance +**Objective**: Ensure that the system remains responsive and performs well under load. +1. Open multiple files in the IDE. +2. Start dictation in one file. +3. While dictation is ongoing, switch to another file and edit text manually. +4. Verify that: + - The IDE remains responsive. + - There are no lags or freezes in either the dictation or manual editing processes. + + +###### TC5: Stop Dictation Midway +**Objective**: Verify that stopping the dictation midway works correctly. +1. Open a project and a file in the IDE. +2. Trigger the `VoiceToTextAction`. +3. Start dictating and then abruptly close the status dialog to stop dictation. +4. Verify that: + - The dictation stops immediately. + - Partially dictated text remains in the editor and is correct up to the point of stopping. + + +##### Test Data: +- Various sentences covering simple to complex structures for dictation. +- Texts with technical terms and IDE-specific terminology. + + +##### Reporting: +- Document the results for each test case. +- Include screenshots or video captures where necessary. +- Log any discrepancies or issues in a defect tracking system. + + +##### Cleanup: +- Restore any settings changed during testing. +- Remove test artifacts from the IDE environment. + +This manual test plan will help ensure that the `VoiceToTextAction` class functions as expected and provides a robust feature within the IDE environment. + +# generic\CreateFileFromDescriptionAction.kt + + +#### Manual Test Plan for `CreateFileFromDescriptionAction` Class + + +##### Objective: +To verify that the `CreateFileFromDescriptionAction` class functions correctly, creating new files based on directives provided by the user, and handling file paths and naming conflicts appropriately. + + +##### Test Environment Setup: +- Ensure the testing environment has access to a Java development setup with necessary libraries installed. +- Clone or have access to the repository containing the `CreateFileFromDescriptionAction` class. +- Setup an instance of the `AppSettingsState` with appropriate configurations for the chat model and temperature settings. + + +##### Test Data: +- Various directives for file creation, ranging from simple to complex requirements. +- Different project structures to test path calculations and file creation in nested directories. + + +##### Test Cases: + + +###### Test Case 1: Basic File Creation +**Objective**: Verify that a simple file can be created with basic content. +**Steps**: +1. Set up a directive that specifies creating a simple Java class file. +2. Invoke the `processSelection` method with a mock `SelectionState` pointing to a valid project directory. +3. Check if the file is created in the correct location with the specified content. + + +###### Test Case 2: File Creation with Path Calculation +**Objective**: Test the path calculation logic when the selected file is in a subdirectory or uses relative paths. +**Steps**: +1. Provide a directive that includes creating a file in a subdirectory. +2. Use a `SelectionState` where `selectedFile` includes relative paths (e.g., `../src/Main.java`). +3. Ensure the file is created in the correct directory relative to the project root. + + +###### Test Case 3: Handling Existing Files +**Objective**: Ensure the system correctly handles scenarios where the file already exists. +**Steps**: +1. Create a directive to generate a file that already exists in the target directory. +2. Run the `processSelection` method and check if the file is renamed appropriately to avoid overwriting the existing file. + + +###### Test Case 4: Error Handling +**Objective**: Verify that the system handles errors gracefully, such as invalid paths or permissions issues. +**Steps**: +1. Set up a directive that tries to create a file in a non-writable directory. +2. Attempt to create the file and catch any exceptions. +3. Verify that appropriate error messages are logged or returned. + + +###### Test Case 5: Complex File Content +**Objective**: Test the system's ability to handle complex file content generation based on the directive. +**Steps**: +1. Provide a complex directive that requires generating a file with multiple classes or special characters. +2. Check if the file is created with the correct content, preserving all special formatting and characters. + + +###### Test Case 6: Integration with Chat Model +**Objective**: Ensure that the chat model integration works correctly and the responses are parsed correctly. +**Steps**: +1. Mock the chat model response to return a predetermined output. +2. Verify that the `generateFile` method correctly interprets the chat model's response and creates the file accordingly. + + +##### Reporting: +- Document all test results, including success or failure status for each test case. +- Include any error messages or stack traces in case of failures. +- Provide recommendations for bug fixes or enhancements based on the test outcomes. + + +##### Cleanup: +- Remove any files or directories created during testing. +- Reset any configurations changed during the test setup. + +This manual test plan will help ensure that the `CreateFileFromDescriptionAction` class meets its functional requirements and handles various scenarios gracefully. + +# generic\DiffChatAction.kt + + +#### Manual Test Plan for DiffChatAction + + +##### Objective: +To validate the functionality of the `DiffChatAction` class, ensuring it correctly handles user interactions for generating and applying code diffs through a chat interface. + + +##### Pre-requisites: +1. IntelliJ IDEA or compatible IDE installed. +2. Plugin containing the `DiffChatAction` class installed and enabled in the IDE. +3. Access to a project with source code files in the IDE. +4. Network access for server communication. + + +##### Test Environment: +- Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur] +- IDE: IntelliJ IDEA [Specify version] +- Plugin Version: [Specify version] + + +##### Test Data: +- Source code files in various programming languages supported by the plugin. + + +##### Test Cases: + + +###### TC1: Basic Invocation and UI Display +**Objective**: Verify that the DiffChatAction can be triggered and the UI is displayed correctly. +1. Open a source code file in the IDE. +2. Right-click and select the `Diff Chat` option from the context menu. +3. Observe that a new browser window or tab opens displaying the chat interface. +4. Verify that the chat interface loads without errors and displays the initial system prompt correctly. + + +###### TC2: Code Selection Handling +**Objective**: Ensure the action correctly handles both selected and full document text. +1. Select a portion of text in an open document and invoke the `Diff Chat` action. +2. Verify that only the selected text is sent to the chat interface. +3. Repeat the test without any text selected and verify that the entire document text is sent to the chat interface. + + +###### TC3: Diff Formatting and Response Rendering +**Objective**: Test the system's ability to handle diff formatting in user responses and render the proposed changes. +1. Start a chat session with some code. +2. Input a diff formatted response as per the system's instructions. +3. Verify that the response is rendered correctly in the chat interface, showing visual diff (additions and deletions). +4. Check if the "apply diff" links are functional and correctly modify the code in the IDE when clicked. + + +###### TC4: Error Handling +**Objective**: Ensure the system gracefully handles errors. +1. Input an incorrectly formatted diff response. +2. Verify that the system provides a meaningful error message or guidance. +3. Attempt to invoke the action with no open editor or document, and verify that it fails gracefully, possibly with a user notification. + + +###### TC5: Session Management +**Objective**: Confirm that sessions are handled correctly. +1. Open multiple instances of the chat interface with different code files. +2. Ensure that each session maintains its state independently. +3. Close and reopen the browser or tab, and verify if the session persists or restarts correctly based on the designed behavior. + + +###### TC6: Network Failure Simulation +**Objective**: Test the robustness of the application under network failure conditions. +1. Start a chat session and then simulate a network failure (e.g., by disabling network connectivity). +2. Attempt to submit a diff and observe how the application behaves (e.g., error messages, retry mechanisms). +3. Restore network connectivity and verify if the session resumes or needs to be restarted. + + +##### Post-Test Cleanup: +- Close all open sessions and browser instances. +- Restore any modified code files to their original state if not done automatically by the test. + + +##### Reporting: +Document all findings with screenshots and logs where applicable. Report any deviations from expected outcomes, including any UI issues, functionality bugs, or crashes. + +# generic\LineFilterChatAction.kt + + +#### Manual Test Plan for LineFilterChatAction + + +##### Objective: +To validate the functionality of the `LineFilterChatAction` class, ensuring that it correctly handles user interactions, processes code, and integrates with the chat system for code assistance. + + +##### Prerequisites: +- IntelliJ IDEA or compatible IDE installed. +- Plugin containing the `LineFilterChatAction` installed and enabled in the IDE. +- Access to a project with source code files in the IDE. +- Network access for the chat server functionality. + + +##### Test Environment: +- Operating System: [Specify OS] +- IDE Version: [Specify IDE version] +- Plugin Version: [Specify Plugin version] +- Dependencies: Ensure all dependencies are correctly configured, including necessary servers and services running. + + +##### Test Cases: + + +###### TC1: Basic Invocation +**Objective**: Verify that the action can be triggered from the IDE. +1. Open a source code file in the IDE. +2. Select a portion of code or simply place the cursor within the document. +3. Trigger the `LineFilterChatAction` via its assigned shortcut or menu entry. +4. **Expected Result**: + - The action initializes without errors. + - A browser window/tab opens pointing to the chat interface. + + +###### TC2: No Selection Handling +**Objective**: Verify the action's behavior when no text is selected. +1. Open a source code file and ensure no text is selected. +2. Trigger the `LineFilterChatAction`. +3. **Expected Result**: + - The entire text of the current document is used as input for the chat session. + + +###### TC3: Error Handling - Unsupported File Type +**Objective**: Verify that the action handles unsupported file types gracefully. +1. Open a file of an unsupported type (e.g., a binary file). +2. Attempt to trigger the `LineFilterChatAction`. +3. **Expected Result**: + - The action does not proceed. + - An appropriate error message or notification is displayed. + + +###### TC4: Chat Interaction +**Objective**: Test the chat functionality with the AI. +1. Trigger the action with a selected portion of code. +2. In the opened chat interface, ask specific questions related to the code. +3. **Expected Result**: + - The AI responds accurately based on the provided code context. + - Responses include appropriate references to the code lines. + + +###### TC5: Session Management +**Objective**: Ensure that sessions are handled and stored correctly. +1. Open multiple code files and trigger the action in each. +2. Interact with the chat in each session. +3. Navigate between different chat sessions. +4. **Expected Result**: + - Each session maintains its state independently. + - Switching between sessions displays the correct chat history and code context. + + +###### TC6: Network Failure Handling +**Objective**: Verify the system's resilience to network issues. +1. Trigger the action with a network connection active. +2. During the chat session, simulate a network failure (e.g., disable network connectivity). +3. Attempt to continue the interaction. +4. Restore network connectivity and try interacting again. +5. **Expected Result**: + - During network failure, the system should handle the loss gracefully, possibly with error notifications. + - After connectivity is restored, the system should resume normal operation. + + +###### TC7: Code Update Reflection +**Objective**: Verify that updates to code are reflected in the chat when the action is re-triggered. +1. Open a source code file, trigger the action, and start a chat session. +2. Close the chat, modify the code in the IDE, and trigger the action again. +3. **Expected Result**: + - The new chat session should reflect the updated code. + + +##### Reporting: +- Document all test results, noting any failures or unexpected behaviors. +- Capture screenshots or logs where applicable. +- Provide feedback and suggestions for improvement based on test outcomes. + + +##### Cleanup: +- Close all open sessions and browser tabs related to testing. +- Restore any settings changed during testing to their original state. + +This manual test plan will help ensure that the `LineFilterChatAction` behaves as expected under various conditions and usage scenarios. + +# generic\MultiStepPatchAction.kt + + +#### Manual Test Plan for MultiStepPatchAction + + +##### Objective: +To verify the functionality and robustness of the `MultiStepPatchAction` class, ensuring it correctly handles user interactions, processes data, and integrates with the system environment and other components. + + +##### Test Environment: +- IDE (e.g., IntelliJ IDEA) with the plugin installed. +- Access to a local or remote development server. +- Necessary permissions to read from and write to the project directories. +- Java Development Kit (JDK) installed. + + +##### Pre-conditions: +- The plugin containing `MultiStepPatchAction` is properly installed and enabled in the IDE. +- The user has a project open in the IDE with multiple files for testing. + + +##### Test Cases: + +1. **Initialization Test** + - **Objective**: Ensure the `MultiStepPatchAction` initializes correctly within the IDE environment. + - **Steps**: + 1. Start the IDE. + 2. Open a project. + 3. Trigger the `MultiStepPatchAction`. + - **Expected Result**: The action initializes without errors, and the Auto Dev Assistant UI is accessible. + +2. **UI Accessibility Test** + - **Objective**: Verify that the Auto Dev Assistant UI opens in the default browser and displays correctly. + - **Steps**: + 1. Trigger the `MultiStepPatchAction`. + 2. Observe the browser opening automatically. + - **Expected Result**: The Auto Dev Assistant UI is displayed correctly in the browser with all elements visible. + +3. **Session Handling Test** + - **Objective**: Confirm that sessions are handled correctly, allowing multiple instances without conflict. + - **Steps**: + 1. Trigger the `MultiStepPatchAction` multiple times with different projects. + 2. Navigate between different sessions in the browser. + - **Expected Result**: Each session should maintain its state independently. + +4. **File Selection and Data Storage Interaction** + - **Objective**: Ensure that the action correctly handles file selections and interacts with the data storage. + - **Steps**: + 1. Select different folders and files in the IDE. + 2. Trigger the `MultiStepPatchAction`. + 3. Check if the selected files are correctly recognized and listed in the UI. + - **Expected Result**: The selected files should be correctly passed to the Auto Dev Assistant and displayed in the UI. + +5. **Task Generation and Display** + - **Objective**: Test the generation and display of tasks based on user input. + - **Steps**: + 1. Provide a specific development directive in the UI. + 2. Observe the tasks generated by the system. + - **Expected Result**: Tasks relevant to the user's directive are generated and displayed correctly. + +6. **Error Handling Test** + - **Objective**: Ensure that the system gracefully handles errors. + - **Steps**: + 1. Trigger scenarios likely to produce errors (e.g., invalid file paths, unsupported operations). + 2. Observe the system's response. + - **Expected Result**: Errors are handled gracefully, with informative messages displayed to the user without crashing the system. + +7. **Concurrency Test** + - **Objective**: Verify that the system handles concurrent operations without data corruption or crashes. + - **Steps**: + 1. Trigger multiple instances of `MultiStepPatchAction` simultaneously. + 2. Perform operations in multiple UI sessions at the same time. + - **Expected Result**: All operations are processed correctly without interference, data corruption, or system crashes. + +8. **Cleanup and Session Termination** + - **Objective**: Confirm that sessions are cleaned up properly after termination. + - **Steps**: + 1. Close the browser or terminate sessions from the UI. + 2. Check system resources and logs for any remnants. + - **Expected Result**: All resources are released, and no session data remains after termination. + + +##### Post-conditions: +- All test data created during the testing should be cleaned up. +- The system should be restored to its initial state before testing. + + +##### Reporting: +- All findings from the test cases should be documented, including any discrepancies from the expected results. +- Severity and priority should be assigned to each finding for further action and resolution. + +This manual test plan provides a structured approach to validate the functionality and reliability of the `MultiStepPatchAction` within a development environment. Adjustments may be necessary based on specific configurations or additional requirements. + +# generic\RedoLast.kt + + +#### Manual Test Plan for RedoLast Action in IntelliJ + + +##### Objective: +To verify that the RedoLast action correctly redoes the last AI Coder action performed in the IntelliJ editor. + + +##### Prerequisites: +- IntelliJ IDEA must be installed and running. +- The AI Coder plugin, including the RedoLast action, must be installed and enabled in IntelliJ. +- A project with at least one file must be open in the editor. + + +##### Test Environment: +- Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur] +- IntelliJ IDEA version: [Specify version - e.g., 2021.3] +- AI Coder plugin version: [Specify version] + + +##### Test Data: +- Various code files in different languages supported by the plugin (e.g., Java, Kotlin, Python). + + +##### Test Cases: + + +###### TC1: Basic Redo Functionality +1. **Objective**: Ensure that the RedoLast action can redo a simple undone action. +2. **Steps**: + - Open a file in the editor. + - Perform a simple action (e.g., typing a line of code). + - Undo the action using IntelliJ's built-in undo feature. + - Trigger the RedoLast action. +3. **Expected Result**: The undone action should be redone correctly. + + +###### TC2: Redo After Multiple Actions +1. **Objective**: Verify that RedoLast redoes the last undone action after multiple changes. +2. **Steps**: + - Open a file and perform multiple editing actions (e.g., add several lines of code). + - Undo several actions one by one. + - Trigger the RedoLast action. +3. **Expected Result**: Only the last undone action should be redone. + + +###### TC3: Redo With No Prior Action +1. **Objective**: Check the behavior when there is no action to redo. +2. **Steps**: + - Open a new or existing file. + - Ensure no actions are performed or undo any performed actions. + - Trigger the RedoLast action. +3. **Expected Result**: No changes should occur in the editor. The action should handle the absence of redoable actions gracefully. + + +###### TC4: Redo in Different File Types +1. **Objective**: Ensure that RedoLast works across files of different types. +2. **Steps**: + - Repeat TC1 for different file types (e.g., .java, .kt, .py). +3. **Expected Result**: The RedoLast action should function correctly regardless of the file type. + + +###### TC5: Redo After Restarting IntelliJ +1. **Objective**: Verify that RedoLast can still function after restarting IntelliJ. +2. **Steps**: + - Open a file, perform some actions, and undo at least one. + - Close and reopen IntelliJ. + - Open the same file and trigger the RedoLast action. +3. **Expected Result**: The last undone action should be redone correctly, assuming session persistence for undo/redo stacks. + + +##### Reporting: +- Document the outcome of each test case. +- Capture any discrepancies from the expected results as defects. +- Include screenshots or video captures if applicable. + + +##### Cleanup: +- Revert any changes made to the code files during testing to maintain a clean state. + +This test plan ensures comprehensive coverage of the RedoLast functionality within the AI Coder plugin, addressing different scenarios and edge cases. + +# generic\MultiDiffChatAction.kt + + +#### Manual Test Plan for MultiDiffChatAction + + +##### Objective: +To ensure that the `MultiDiffChatAction` class functions correctly across various scenarios, handling file differences and chat interactions as expected within an IDE environment. + + +##### Test Environment: +- IDE with plugin support (e.g., IntelliJ IDEA) +- Access to the plugin that includes the `MultiDiffChatAction` +- Necessary permissions to read/write files and access the internet +- Desktop environment capable of opening a web browser + + +##### Pre-conditions: +- The plugin containing `MultiDiffChatAction` is installed and enabled in the IDE. +- Test files with various programming languages are available within the project or workspace. + + +##### Test Cases: + + +###### TC1: Basic Functionality Check +**Objective**: Verify that the action can be triggered and the chat interface opens in the default browser. +1. Right-click on a file or a selection of files in the project explorer. +2. Select the `MultiDiffChat` action. +3. **Expected Result**: + - A new browser tab opens pointing to the chat interface. + - The chat interface displays the initial code summary correctly. + + +###### TC2: Multi-file Handling +**Objective**: Ensure that the action correctly handles multiple files. +1. Select multiple files with different extensions from the project explorer. +2. Trigger the `MultiDiffChat` action. +3. **Expected Result**: + - The chat interface shows a code summary for each selected file. + - Language detection works as expected for different file types. + + +###### TC3: No File Selected +**Objective**: Check the behavior when no file is selected. +1. Ensure no file is selected in the project explorer. +2. Trigger the `MultiDiffChat` action. +3. **Expected Result**: + - An error message appears indicating that no file was selected or an automatic fallback to a default directory occurs. + + +###### TC4: File Updates +**Objective**: Test if the code updates are correctly applied to the files. +1. Select a file and trigger the `MultiDiffChat` action. +2. In the chat interface, submit a code change suggestion. +3. Accept the change in the IDE. +4. **Expected Result**: + - The file in the IDE is updated with the new code. + - The document is saved automatically if changes are applied. + + +###### TC5: Error Handling +**Objective**: Ensure that errors are handled gracefully. +1. Manipulate the environment to simulate an error (e.g., permissions issues, network failures). +2. Trigger the `MultiDiffChat` action. +3. **Expected Result**: + - Appropriate error messages are displayed. + - The system logs the error details for debugging. + + +###### TC6: Session Management +**Objective**: Verify that sessions are managed correctly. +1. Open the chat interface using the `MultiDiffChat` action. +2. Close the browser or navigate away from the chat page. +3. Reopen the chat interface. +4. **Expected Result**: + - The previous session should either continue where it left off or a new session should start cleanly. + + +###### TC7: Browser Compatibility +**Objective**: Ensure the chat interface works across different browsers. +1. Trigger the `MultiDiffChat` action using different browsers (e.g., Chrome, Firefox, Edge). +2. **Expected Result**: + - The chat interface functions correctly in all tested browsers. + + +##### Post-conditions: +- Verify that all files are intact and contain expected changes if any were made. +- Ensure no residual data or sessions are left that could affect subsequent tests. + + +##### Cleanup: +- Revert any changes made to files during testing. +- Clear any test data or configurations that were set up for testing purposes. + + +#### Notes: +- Each test should be documented with screenshots or video captures where applicable. +- Any anomalies or deviations from the expected results should be logged and investigated. + +# generic\GenerateDocumentationAction.kt + + +#### Manual Test Plan for GenerateDocumentationAction + + +##### Objective +To verify that the `GenerateDocumentationAction` class functions correctly, allowing users to compile documentation from selected files using AI-generated content. + + +##### Test Environment +- IDE: IntelliJ IDEA (or compatible IDE) +- Plugin: Ensure the plugin containing `GenerateDocumentationAction` is installed and enabled. +- Operating System: Windows, macOS, or Linux + + +##### Pre-requisites +- The plugin containing the `GenerateDocumentationAction` is installed and enabled in the IDE. +- Sample project files are available within the IDE for testing. + + +##### Test Cases + + +###### TC1: Basic Functionality Test +**Objective**: To verify that the action compiles documentation from selected files. +1. **Steps**: + - Right-click on a folder containing multiple source files. + - Select the "Compile Documentation" option. + - In the dialog, select multiple files to process. + - Enter a specific AI instruction in the provided text area. + - Specify an output filename. + - Click OK to generate the documentation. +2. **Expected Result**: + - A markdown file with the specified name is created in the same directory. + - The file contains compiled documentation based on the AI transformation of the selected files. + + +###### TC2: Validation of Output File Naming +**Objective**: To verify that the system handles existing filenames correctly by creating a new file with an incremented index. +1. **Steps**: + - Repeat TC1 but specify an output filename that already exists. +2. **Expected Result**: + - A new file is created with an incremented index in its name (e.g., `compiled_documentation.1.md`). + + +###### TC3: AI Instruction Impact +**Objective**: To verify that changing the AI instruction affects the generated documentation content. +1. **Steps**: + - Perform TC1 with a basic instruction. + - Repeat the process with a more detailed or different instruction. +2. **Expected Result**: + - The content of the generated documentation should reflect the differences dictated by the AI instructions. + + +###### TC4: No Files Selected +**Objective**: To verify the system behavior when no files are selected for processing. +1. **Steps**: + - Open the "Compile Documentation" dialog. + - Deselect all files. + - Provide an AI instruction and output filename. + - Click OK. +2. **Expected Result**: + - No output file is created. + - A user-friendly message or indication that no files were processed. + + +###### TC5: Error Handling +**Objective**: To verify that the system handles errors gracefully (e.g., permission issues, corrupted files). +1. **Steps**: + - Introduce a controlled error scenario such as permissions restrictions on a file. + - Attempt to compile documentation including the problematic file. +2. **Expected Result**: + - The process should not crash. + - An error message should be displayed, indicating the nature of the problem. + + +###### TC6: UI Elements and Responsiveness +**Objective**: To verify that all UI elements are responsive and function as expected. +1. **Steps**: + - Open the "Compile Documentation" dialog. + - Interact with all UI elements (checkboxes, text fields, buttons). +2. **Expected Result**: + - All elements should be responsive. + - Changes in the UI should reflect immediately (e.g., text updates, checkbox selections). + + +##### Post-Test Cleanup +- Remove any test files or directories created during testing. +- Restore any settings changed during testing to their original state. + + +##### Reporting +- Document any discrepancies from the expected results. +- Capture screenshots or logs if applicable. +- Provide a detailed report to the development team for any failures or bugs encountered. + +# generic\ReplaceWithSuggestionsAction.kt + + +#### Manual Test Plan for `ReplaceWithSuggestionsAction` Class + + +##### Objective +To verify that the `ReplaceWithSuggestionsAction` class functions correctly, providing appropriate suggestions for text replacement based on the selected text within an IDE environment. + + +##### Pre-requisites +- IntelliJ IDEA or a compatible IDE installed. +- Plugin containing the `ReplaceWithSuggestionsAction` class is installed and enabled in the IDE. +- A project is open in the IDE with at least one editable file. + + +##### Test Environment +- Operating System: [Specify OS] +- IDE Version: [Specify IDE version] +- Plugin Version: [Specify Plugin version] + + +##### Test Data +- Various code snippets and text blocks of varying lengths and contexts. + + +##### Test Cases + + +###### TC1: Basic Functionality Test +**Objective**: Ensure that the action triggers and provides suggestions. +**Steps**: +1. Open a file in the IDE. +2. Select a portion of text. +3. Trigger the `ReplaceWithSuggestionsAction`. +4. Observe if the suggestions dialog appears. + +**Expected Result**: A dialog with suggested replacements should appear. + + +###### TC2: No Selection Test +**Objective**: Verify behavior when no text is selected. +**Steps**: +1. Ensure no text is selected. +2. Trigger the `ReplaceWithSuggestionsAction`. +3. Observe the behavior. + +**Expected Result**: No action should be taken, or a user-friendly message should be displayed indicating no text is selected. + + +###### TC3: Large Text Selection +**Objective**: Test the action with a large text selection. +**Steps**: +1. Select a large block of text (e.g., several paragraphs or a complete function). +2. Trigger the `ReplaceWithSuggestionsAction`. +3. Observe the suggestions provided. + +**Expected Result**: The action should handle large texts gracefully, possibly truncating or summarizing the context appropriately. + + +###### TC4: Edge Case with Special Characters +**Objective**: Ensure special characters in the text do not cause errors. +**Steps**: +1. Select text that includes special characters (e.g., symbols, non-ASCII characters). +2. Trigger the `ReplaceWithSuggestionsAction`. +3. Check if the suggestions are generated without errors. + +**Expected Result**: Suggestions are generated without errors, and special characters are handled correctly. + + +###### TC5: Response to API Failure +**Objective**: Determine the behavior when the backend API fails or is unavailable. +**Steps**: +1. Simulate API failure (e.g., by disconnecting from the network or using a mock to force a failure). +2. Trigger the `ReplaceWithSuggestionsAction`. +3. Observe the behavior. + +**Expected Result**: The action should handle API failures gracefully, notifying the user of the issue without crashing. + + +###### TC6: Performance Test +**Objective**: Ensure the action performs well under typical conditions. +**Steps**: +1. Select a reasonable amount of text. +2. Trigger the `ReplaceWithSuggestionsAction` multiple times in quick succession. +3. Observe any lag or performance degradation. + +**Expected Result**: The action should perform efficiently without significant delays or resource consumption spikes. + + +##### Reporting +- Document all test results, including any deviations from expected outcomes. +- Capture screenshots or video recordings for UI-related tests. +- Log any errors or exceptions encountered during testing. + + +##### Post-Test Cleanup +- Restore any settings or configurations changed during testing to their original state. +- Close and reopen the IDE to clear any temporary states or caches if necessary. + +This manual test plan will help ensure that the `ReplaceWithSuggestionsAction` behaves as expected across various scenarios and handles edge cases and errors gracefully. + +# generic\PlanAheadAction.kt + + +#### Manual Test Plan for PlanAheadAction and TaskRunnerApp + + +##### Objective: +To verify the functionality and robustness of the PlanAheadAction and TaskRunnerApp components, ensuring they handle task creation, session management, and user interactions correctly. + + +##### Test Environment: +- IDE with the plugin installed (e.g., IntelliJ IDEA) +- Access to a local or remote server environment where the AppServer is running +- Necessary permissions to read and write files and execute commands on the system + + +##### Test Data: +- Various project files including different file types and sizes +- User input scenarios including valid and invalid commands +- Configuration settings for different user roles and permissions + + +##### Test Cases: + + +###### TC1: Initialization and Session Creation +**Objective**: Verify that a new session is created successfully when the action is triggered. +1. Trigger the PlanAheadAction from the IDE. +2. Check if a new session ID is generated and stored correctly. +3. Verify that the session is associated with the correct project and user. + + +###### TC2: Folder and File Selection +**Objective**: Ensure the application correctly handles the selection of folders and files. +1. Select a folder and trigger the PlanAheadAction. +2. Verify that the application uses the selected folder as the root. +3. Select a file and trigger the PlanAheadAction. +4. Verify that the application identifies the correct module root based on the file location. + + +###### TC3: Task Creation and Execution +**Objective**: Test the creation and execution of tasks based on user input. +1. Input a valid task description and trigger task creation. +2. Check if the task is created with the correct parameters and dependencies. +3. Execute the task and verify that the expected output or changes are made. +4. Input invalid or incomplete task descriptions and verify that errors are handled gracefully. + + +###### TC4: User Interface and Interaction +**Objective**: Ensure that the user interface displays the correct information and responds to user interactions. +1. Check if the UI correctly displays the session and task details. +2. Use the UI to modify task settings and trigger updates. +3. Verify that changes are reflected in the task execution. +4. Test the responsiveness of the UI under different network conditions. + + +###### TC5: Error Handling and Logging +**Objective**: Verify that the application handles errors properly and logs them as expected. +1. Simulate various error conditions (e.g., file not found, access denied, server error). +2. Verify that the application displays appropriate error messages to the user. +3. Check the logs to ensure that errors are recorded correctly. + + +###### TC6: Security and Permissions +**Objective**: Test the application’s handling of security and permissions. +1. Attempt to execute tasks that require elevated permissions without the necessary rights. +2. Verify that the application prevents unauthorized actions and logs the attempts. +3. Test the application with users having different roles and verify that permissions are enforced according to the role. + + +###### TC7: Performance and Scalability +**Objective**: Assess the performance and scalability of the application under load. +1. Trigger multiple sessions and tasks simultaneously. +2. Monitor the performance metrics such as response time, CPU, and memory usage. +3. Verify that the application scales well and maintains performance as the number of tasks increases. + + +##### Test Reporting: +- Document the results of each test case, including the steps taken, expected outcomes, actual outcomes, and any discrepancies. +- Include screenshots or logs where applicable to provide evidence of the test results. +- Summarize the findings and provide recommendations for improvements or bug fixes. + + +##### Conclusion: +This manual test plan aims to cover critical functionalities of the PlanAheadAction and TaskRunnerApp to ensure they meet the required standards for performance, usability, and reliability. Regular testing and updates based on the findings will help maintain the quality of the application. + +# generic\WebDevelopmentAssistantAction.kt + + +#### Manual Test Plan for WebDevelopmentAssistantAction + + +##### Objective: +To ensure that the `WebDevelopmentAssistantAction` class and its associated components function correctly across various scenarios, handling user interactions, file operations, and server communications effectively. + + +##### Test Environment Setup: +1. **IDE Setup**: Ensure IntelliJ IDEA is installed and configured. +2. **Plugin Installation**: Install the plugin containing the `WebDevelopmentAssistantAction` class. +3. **Server Setup**: Verify that the `AppServer` is up and running. +4. **File System**: Prepare a directory structure with various file types to simulate user projects. +5. **Browser Setup**: Ensure a default browser is set and functional. + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: Verify that the action initializes and opens a browser window to the correct URL. +1. **Steps**: + - Right-click on a folder in the project explorer. + - Select the `Web Dev Assistant v1.1` action. +2. **Expected Results**: + - A new browser window/tab opens. + - The URL corresponds to the `AppServer` URL with the appropriate session ID appended. + + +###### TC2: Directory Selection Validation +**Objective**: Ensure the action is disabled when a non-directory file is selected. +1. **Steps**: + - Right-click on a non-directory file in the project explorer. + - Observe the availability of the `Web Dev Assistant v1.1` action. +2. **Expected Results**: + - The action should be disabled or not visible. + + +###### TC3: Session Handling +**Objective**: Test if new sessions are correctly created and managed. +1. **Steps**: + - Trigger the action multiple times with different selected directories. + - Observe the creation of new sessions. +2. **Expected Results**: + - Each action trigger should result in a new session. + - Each session should have a unique session ID. + + +###### TC4: Error Handling +**Objective**: Verify that the system handles errors gracefully (e.g., failure to open a browser). +1. **Steps**: + - Temporarily modify system settings to disable the default browser. + - Trigger the action. +2. **Expected Results**: + - An appropriate error message should be logged. + - The system should not crash. + + +###### TC5: User Message Handling +**Objective**: Ensure that user messages are correctly processed and responded to within the application. +1. **Steps**: + - Use the browser interface to send a message through the web application. + - Observe the response and any changes in the UI. +2. **Expected Results**: + - The message should be processed. + - A valid response should be displayed in the UI. + + +###### TC6: File Generation and Linking +**Objective**: Test the generation of HTML, CSS, and JavaScript files based on user input. +1. **Steps**: + - Provide specific instructions via the web interface for generating web resources. + - Check the generated files and their content. +2. **Expected Results**: + - Files should be correctly generated in the specified paths. + - Files should contain content that matches the instructions provided. + + +###### TC7: Code Review and Feedback Integration +**Objective**: Verify that code reviews and feedback are correctly applied to the generated code. +1. **Steps**: + - Generate some initial code files. + - Use the provided interface to request a code review. + - Apply suggested changes via the interface. +2. **Expected Results**: + - The system should provide valid code modifications. + - Users should be able to apply these modifications directly from the interface. + + +###### TC8: Multi-Session Interaction +**Objective**: Ensure that multiple sessions can run concurrently without interference. +1. **Steps**: + - Open multiple sessions from different projects. + - Interact with each session independently. +2. **Expected Results**: + - Actions in one session should not affect any other sessions. + + +##### Test Data: +- Sample directories with different structures and content. +- Sample user messages for generating web resources. +- Code snippets for review. + + +##### Reporting: +- Document all test results with screenshots and logs. +- Report any discrepancies from expected results for further investigation. + + +##### Cleanup: +- Remove any test-specific configurations and files. +- Restart the server to clear all sessions and data. + +This manual test plan will help ensure that the `WebDevelopmentAssistantAction` behaves as expected under various conditions and handles user interactions correctly. + +# markdown\MarkdownImplementActionGroup.kt + + +#### Manual Test Plan for MarkdownImplementActionGroup + + +##### Objective +To verify that the `MarkdownImplementActionGroup` and its child actions (`MarkdownImplementAction`) function correctly within an IDE environment, enabling users to convert selected text into various programming languages within a Markdown context. + + +##### Test Environment +- IDE (e.g., IntelliJ IDEA) +- Java Development Kit (JDK) +- Plugin installed and enabled in the IDE + + +##### Pre-conditions +- The plugin containing the `MarkdownImplementActionGroup` must be installed and enabled in the IDE. +- A project must be open in the IDE with at least one Markdown file. + + +##### Test Cases + + +###### TC1: Action Visibility and Enablement +**Objective**: Ensure that the action group is only visible and enabled when a Markdown file is active and text is selected. +1. Open a non-Markdown file and verify that the action group is neither visible nor enabled. +2. Open a Markdown file but do not select any text. Verify that the action group is visible but not enabled. +3. Select text in the Markdown file and verify that the action group is both visible and enabled. + + +###### TC2: Action Listing +**Objective**: Verify that all supported languages are listed under the action group when invoked. +1. Open a Markdown file and select some text. +2. Activate the action group and verify that all expected programming languages are listed (e.g., SQL, Java, Python, etc.). + + +###### TC3: Code Conversion Functionality +**Objective**: Test the conversion functionality for each supported language. +1. For each language in the `markdownLanguages` list: + - Select a block of text in a Markdown file. + - Trigger the `MarkdownImplementAction` for the language. + - Verify that the selected text is converted appropriately into the target language and wrapped in the correct Markdown code block syntax. + - Check for proper escaping and indentation of the generated code. + + +###### TC4: Error Handling +**Objective**: Ensure that the system handles errors gracefully when the conversion API fails or returns an error. +1. Simulate API failure scenarios (e.g., network issues, API errors). +2. Attempt to convert selected text using any language action. +3. Verify that the system provides a user-friendly error message and does not crash or hang. + + +###### TC5: Performance +**Objective**: Ensure that the action completes within a reasonable time frame. +1. Select a relatively large block of text. +2. Trigger the conversion for a complex language like Java or C++. +3. Measure the time taken to complete the conversion and ensure it is reasonable (e.g., a few seconds). + + +###### TC6: User Interface Consistency +**Objective**: Verify that the action group and actions maintain consistent UI presentation. +1. Check that all actions have correct and consistent naming and descriptions as per their language. +2. Ensure that icons (if any) and text formatting are consistent across all instances of the actions. + + +##### Post-conditions +- No permanent changes should be made to the project files unless explicitly saved by the tester. +- The IDE should remain stable and responsive after testing. + + +##### Reporting +- All issues found during testing should be documented with screenshots and detailed replication steps. +- Performance metrics should be recorded and analyzed. +- Suggestions for improvement or additional test cases should be submitted for review. + +This manual test plan will help ensure that the `MarkdownImplementActionGroup` behaves as expected, providing a reliable feature for users to convert text into various programming languages directly within Markdown files. + +# markdown\MarkdownListAction.kt + + +#### Manual Test Plan for MarkdownListAction + + +##### Objective: +To verify that the `MarkdownListAction` class functions correctly within an IDE environment, specifically focusing on generating and appending new list items to existing markdown lists in a markdown file. + + +##### Test Environment: +- IDE (e.g., IntelliJ IDEA) +- Java Development Kit (JDK) +- Plugin or module containing the `MarkdownListAction` class +- Sample markdown files with various list formats + + +##### Pre-requisites: +- The plugin/module containing the `MarkdownListAction` is installed and enabled in the IDE. +- Open a project that contains at least one markdown file with predefined lists. + + +##### Test Cases: + + +###### TC1: Basic Functionality Test +**Objective**: Ensure that the action appends new list items correctly to a simple markdown list. +1. Open a markdown file containing a simple list (e.g., `- Item 1`). +2. Place the cursor within the list. +3. Trigger the `MarkdownListAction`. +4. **Expected Result**: New items are appended to the list, maintaining the same list format. + + +###### TC2: Multiple List Types +**Objective**: Verify that the action handles different bullet types correctly. +1. Open a markdown file containing lists with different bullet types (`-`, `*`, `+`). +2. Place the cursor within each type of list and trigger the action. +3. **Expected Result**: New items should match the bullet type of the existing list. + + +###### TC3: Nested Lists +**Objective**: Test the action's ability to handle nested lists. +1. Open a markdown file with nested lists. +2. Place the cursor in a nested list and trigger the action. +3. **Expected Result**: New items should be added correctly within the nested structure, respecting indentation. + + +###### TC4: List with Task Boxes +**Objective**: Ensure the action can handle markdown task lists. +1. Open a markdown file with a task list (e.g., `- [ ] Task 1`). +2. Place the cursor in the task list and trigger the action. +3. **Expected Result**: New tasks are added with unchecked boxes. + + +###### TC5: Empty and Null Item Handling +**Objective**: Verify how the action handles empty or null existing items. +1. Open a markdown file and create a list with empty items or simulate a scenario where the list API might return null. +2. Trigger the action. +3. **Expected Result**: The action should handle empty/null gracefully, either by ignoring them or by providing a default item text. + + +###### TC6: Error Handling +**Objective**: Test the action's robustness in handling errors from the list API. +1. Simulate an API failure or error response. +2. Trigger the action. +3. **Expected Result**: The action should not crash the IDE and should provide a meaningful error message. + + +###### TC7: Performance Test +**Objective**: Ensure that the action performs well with large lists. +1. Open a markdown file with a very large list (e.g., 100+ items). +2. Trigger the action. +3. **Expected Result**: The action should complete within a reasonable time without performance degradation. + + +###### TC8: Undo Functionality +**Objective**: Verify that the undo functionality works after the action is performed. +1. Perform any of the above test cases. +2. Use the IDE's undo feature. +3. **Expected Result**: The list should revert to its state before the action was triggered. + + +##### Post-Conditions: +- After testing, ensure no unwanted changes are saved in the markdown files unless specifically testing save functionality. + + +##### Reporting: +- All issues encountered should be documented with screenshots and detailed steps to reproduce. These should be reported to the development team for fixes. + +This manual test plan will help ensure that the `MarkdownListAction` behaves as expected across different scenarios and markdown list formats. + +# git\PrintGitCommitPatchAction.kt + + +#### Manual Test Plan for "Print Git Commit Patch" IntelliJ Plugin Action + + +##### Objective: +To verify that the "Print Git Commit Patch" action in the IntelliJ plugin correctly displays the patch information for a selected Git commit. + + +##### Pre-requisites: +- IntelliJ IDEA must be installed. +- The plugin containing the "Print Git Commit Patch" action must be installed and enabled. +- A project under Git version control must be opened in IntelliJ IDEA. + + +##### Test Environment: +- Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur, etc.] +- IntelliJ IDEA Version: [Specify version - e.g., 2021.3] +- Plugin Version: [Specify version] + + +##### Test Data: +- A Git repository with multiple commits and branches for testing various scenarios. + + +##### Test Cases: + +--- + + +###### TC1: Basic Functionality Test +**Objective**: Ensure the action displays the correct patch for a selected commit. + +**Steps**: +1. Open a project in IntelliJ that is under Git version control. +2. Right-click on a file in the Project Explorer and select 'Git' -> 'Show History'. +3. In the 'History' tab, select a commit that includes changes to the file. +4. Right-click on the selected commit and choose "Print Git Commit Patch". +5. Observe the output. + +**Expected Result**: +- A dialog should appear displaying the patch information for the selected commit. + +--- + + +###### TC2: No Commit Selected +**Objective**: Verify the action handles the scenario where no commit is selected. + +**Steps**: +1. Open a project in IntelliJ that is under Git version control. +2. Without selecting any commit, invoke the "Print Git Commit Patch" action (via any accessible means, such as a shortcut or command palette). + +**Expected Result**: +- A dialog should appear with an error message "No commit selected." + +--- + + +###### TC3: No Project Open +**Objective**: Ensure the action is disabled when there is no open project. + +**Steps**: +1. Close all projects in IntelliJ. +2. Attempt to invoke the "Print Git Commit Patch" action. + +**Expected Result**: +- The action should be disabled and not executable. + +--- + + +###### TC4: Multiple Changes in a Single Commit +**Objective**: Verify that the action correctly handles commits with multiple file changes. + +**Steps**: +1. Open a project in IntelliJ that is under Git version control. +2. Select a commit from the history that includes multiple file changes. +3. Invoke the "Print Git Commit Patch" action. + +**Expected Result**: +- The dialog should display patch information for all changed files in the selected commit, separated by clear demarcations. + +--- + + +###### TC5: Action Visibility and Enablement +**Objective**: Confirm that the action is only visible and enabled when a project is open and a revision is selected. + +**Steps**: +1. Open a project in IntelliJ and ensure no specific revision is selected. +2. Check the visibility and enablement of the "Print Git Commit Patch" action. + +**Expected Result**: +- The action should be disabled and possibly hidden if no revision is selected. + +--- + + +##### Post-Test Cleanup: +- Close any open projects in IntelliJ. +- Restore any settings changed during testing to their original values. + + +##### Reporting: +- Document any discrepancies from the expected results and report them as issues in the issue tracker for the plugin development team to address. Include screenshots and detailed steps to reproduce the issue. + diff --git a/docs/prompt_documentation.md b/docs/prompt_documentation.md new file mode 100644 index 00000000..5b53913a --- /dev/null +++ b/docs/prompt_documentation.md @@ -0,0 +1,1318 @@ +# BaseAction.kt + +The `BaseAction` class serves as an abstract foundation for creating actions within an IntelliJ IDEA plugin, providing a structured way to define actions with optional names, descriptions, and icons. It extends the `AnAction` class from the IntelliJ Platform SDK, allowing it to integrate seamlessly with the IDE's action system. This class encapsulates common functionalities and configurations needed for actions, including logging, API access, and UI interactions. + + +#### Key Components and Logic + + +##### Constructor Parameters +- `name`: An optional parameter for the name of the action. If provided, it will be displayed in the UI. +- `description`: An optional parameter for a short description of what the action does. This can be shown in the UI to provide more context to the user. +- `icon`: An optional parameter for an icon to represent the action visually in the IDE. + + +##### Properties +- `log`: A lazy-initialized logger instance specific to the subclass, used for logging messages and errors. +- `api`: A getter property that provides access to an instance of `OpenAIClient`, facilitating interactions with OpenAI's API through a custom client tailored for IntelliJ IDEA. + + +##### Overridden Methods +- `update(event: AnActionEvent)`: This method is called to determine whether the action is available and visible based on the current context. It sets the `isEnabledAndVisible` property of the action's presentation according to the result of `isEnabled(event)`. +- `actionPerformed(e: AnActionEvent)`: The main method that is invoked when the action is triggered. It logs the action, sets the last event in `IdeaOpenAIClient`, and calls the `handle(e: AnActionEvent)` method. If an exception occurs during execution, it is caught and logged as an error. + + +##### Abstract Methods +- `handle(e: AnActionEvent)`: An abstract method that subclasses must implement to define the action's behavior when it is executed. + + +##### Utility Methods +- `isEnabled(event: AnActionEvent)`: An open method that determines whether the action should be enabled based on the given `AnActionEvent`. By default, it returns `true`, indicating that the action is enabled in all contexts. Subclasses can override this method to provide context-specific logic. + + +##### Companion Object +- Contains a static logger instance for the class and a scheduled thread pool with a single thread. The thread pool can be used for executing tasks asynchronously. + + +#### Usage +To create a custom action using the `BaseAction` class, one must extend this class and implement the `handle(e: AnActionEvent)` method to define what the action does. Optionally, the `isEnabled(event: AnActionEvent)` method can be overridden to control the availability of the action based on the context in which it is invoked. + +This class simplifies the process of creating actions for IntelliJ IDEA plugins by providing a structured approach to handle common requirements such as logging, API interactions, and UI updates. + +# code\DescribeAction.kt + +The `DescribeAction` class is part of a package designed to enhance coding environments with AI-powered features. It extends the `SelectionAction` class, indicating it performs an action based on a selected portion of text within the code editor and returns a `String` result. This class is specifically tasked with generating descriptions for selected code snippets, leveraging a virtual API to communicate with an AI model for natural language processing. + + +#### Key Components and Their Functions + + +##### DescribeAction_VirtualAPI Interface +- **Purpose**: Serves as a contract for the AI-powered code description service. It defines the `describeCode` method that the `DescribeAction` class must implement. This method takes a piece of code, the programming language of the code, and the desired human language for the description as inputs, and returns a `DescribeAction_ConvertedText` object containing the AI-generated description. +- **DescribeAction_ConvertedText Class**: Nested within the `DescribeAction_VirtualAPI` interface, this class is a simple data holder for the AI-generated description (`text`) and the language of the description (`language`). + + +##### Proxy Property +- **Purpose**: Provides access to an instance of the `DescribeAction_VirtualAPI`, created via a `ChatProxy`. This proxy setup allows for dynamic interaction with an AI model specified in the `AppSettingsState` configuration, including parameters like temperature and model choice. +- **Configuration**: Utilizes settings from `AppSettingsState` for customizing the AI's behavior, such as response generation temperature and the choice of AI model. + + +##### getConfig Method +- **Purpose**: Overrides a method from the parent class to provide configuration for the action. In its current implementation, it returns an empty string, indicating no additional configuration is required or it's yet to be implemented. + + +##### processSelection Method +- **Purpose**: The core logic of the `DescribeAction` class, responsible for processing the selected text, generating a description via the AI proxy, and formatting the description according to the code's comment style. +- **Steps**: + 1. Extracts and trims the selected text. + 2. Calls the `describeCode` method of the proxy to get an AI-generated description of the code snippet. + 3. Formats the description to fit within a specified character width (120 characters in this case) and determines the appropriate comment style based on the number of lines in the description and the programming language of the selected text. + 4. Builds and returns a string that combines the formatted description and the original selected text, properly indented and commented. + + +#### Summary +The `DescribeAction` class introduces an AI-powered feature into the coding environment, allowing developers to generate natural language descriptions for code snippets directly within their IDE. This can enhance code readability and documentation efforts, especially in collaborative settings. The class leverages a virtual API to interact with an AI model, dynamically adjusting its behavior based on user-configured settings. + +# code\CustomEditAction.kt + +The `CustomEditAction` class extends the `SelectionAction` class, specifically tailored to handle custom code editing actions within an IDE environment. This class is part of a larger system designed to integrate AI-powered code editing capabilities into the development workflow. Below is a detailed explanation of its components, focusing on the prompt text, configuration, and the closely related logic. + + +#### Overview + +`CustomEditAction` is designed to allow users to apply custom edits to their code using a virtual AI assistant. The class interfaces with a virtual API to process code editing requests based on user instructions. + + +#### Key Components + + +##### VirtualAPI Interface + +- **Purpose**: Defines the contract for the AI-powered code editing service. +- **Methods**: + - `editCode`: Accepts the original code, an operation (instruction), the programming language of the code, and the human language of the instruction. It returns an `EditedText` object containing the edited code and its language. + +- **EditedText Data Class**: + - Holds the edited code (`code`) and its language (`language`). These fields are nullable, allowing for the possibility that the editing process might not result in changes. + + +##### Proxy Property + +- **Purpose**: Provides access to the virtual AI assistant through a `ChatProxy` instance. +- **Configuration**: + - The `ChatProxy` is configured with the `VirtualAPI` class, API settings from `AppSettingsState`, and model preferences. It also includes an example to guide the AI in understanding the expected output format and context. + + +##### getConfig Method + +- **Purpose**: Fetches a user-provided instruction for editing the code. +- **Implementation**: + - Displays an input dialog where the user can enter the editing instruction. + - The method uses `UITools.showInputDialog` to present the dialog, with "Edit Code" as the title and "Instruction:" as the prompt text. + - The input (instruction) is returned as a `String`. If no input is provided, an empty string is returned. + + +##### processSelection Method + +- **Purpose**: Processes the selected code based on the user's instruction. +- **Logic**: + - Checks if the instruction is null or blank. If so, it returns the originally selected text. + - Retrieves the current settings and the preferred human language from `AppSettingsState`. + - Records the instruction in the application's history for future reference. + - Calls the `editCode` method of the `proxy` to request code editing based on the instruction, selected text, and language settings. + - Returns the edited code if available; otherwise, it falls back to the originally selected text. + + +#### Conclusion + +The `CustomEditAction` class encapsulates the logic for integrating AI-powered custom code edits into the development workflow. It leverages a virtual API to process editing instructions, providing an interface for users to enhance their code with the assistance of AI. Through a combination of user input and automated processing, it aims to streamline the code editing process, making it more efficient and tailored to the user's needs. + +# code\CommentsAction.kt + +This Kotlin class, `CommentsAction`, extends the `SelectionAction` to provide functionality for adding comments to a selected block of code within an IDE environment. The class is part of a package designed to integrate AI capabilities into coding workflows, specifically for generating comments in code. Below is a detailed breakdown of its components and functionalities: + + +#### Class Overview +- **Package Name:** `com.github.simiacryptus.aicoder.actions.code` +- **Dependencies:** The class imports necessary modules for its operation, including project configuration (`AppSettingsState`), utility classes (`ComputerLanguage`), and IntelliJ project components (`Project`). It also utilizes a `ChatProxy` for interacting with an AI model. + + +#### Key Methods and Interfaces + + +##### `getConfig(project: Project?): String` +- **Description:** Retrieves configuration settings for the action. In its current implementation, it returns an empty string, indicating no specific configuration is required or implemented. +- **Parameters:** + - `project`: An optional `Project` instance representing the current project context. +- **Returns:** A `String` representing the action's configuration. Currently, returns an empty string. + + +##### `isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean` +- **Description:** Determines if the action supports the provided programming language. +- **Parameters:** + - `computerLanguage`: An optional `ComputerLanguage` enum value representing the programming language of the code selection. +- **Returns:** A `Boolean` value indicating whether the action supports the specified programming language. It returns `true` for all languages except `ComputerLanguage.Text`, indicating it's designed for programming languages rather than plain text. + + +##### `processSelection(state: SelectionState, config: String?): String` +- **Description:** Processes the selected code block to add comments. It utilizes a `ChatProxy` to communicate with an AI model specified in the application settings, sending the selected text and receiving the commented code. +- **Parameters:** + - `state`: A `SelectionState` object containing details about the selected code block, including the text and programming language. + - `config`: An optional `String` representing additional configuration. Currently, it is not used in the method. +- **Returns:** A `String` containing the commented code. If the AI model fails to generate comments, an empty string is returned. + + +##### `CommentsAction_VirtualAPI` Interface +- **Purpose:** Defines the contract for interacting with the AI model to edit code. +- **Method:** `editCode(code: String, operations: String, computerLanguage: String, humanLanguage: String): CommentsAction_ConvertedText` + - **Parameters:** + - `code`: The code block to be commented. + - `operations`: A `String` describing the operation to be performed, e.g., "Add comments to each line explaining the code". + - `computerLanguage`: The programming language of the code. + - `humanLanguage`: The language in which the comments should be written. + - **Returns:** An instance of `CommentsAction_ConvertedText`, containing the commented code. + + +##### `CommentsAction_ConvertedText` Class +- **Description:** Serves as a data container for the AI-generated commented code. +- **Fields:** + - `code`: A nullable `String` holding the commented code. + - `language`: A nullable `String` indicating the language of the comments (not actively used in the current implementation). + + +#### Usage Scenario +This class is designed to be used within an IDE plugin or extension where users can select a block of code and trigger the action to automatically generate and insert comments explaining the code, leveraging AI capabilities. The action checks if the selected code's language is supported (not plain text) and then communicates with an AI model to perform the commenting. + +# code\InsertImplementationAction.kt + +The `InsertImplementationAction` class is part of a system designed to enhance coding efficiency by automatically generating code implementations based on given specifications. This class extends `SelectionAction`, indicating it operates on selections within the editor and returns a `String` result. The core functionality revolves around interpreting selected text or comments as specifications for code to be implemented, then using an AI model to generate the corresponding code. Below is a detailed breakdown of its components and logic: + + +#### VirtualAPI Interface +- **Purpose**: Defines the contract for implementing code generation. It specifies the `implementCode` method, which takes a specification, a prefix, computer language, and human language as inputs and returns a `ConvertedText` object containing the generated code and its language. +- **ConvertedText Class**: Nested within `VirtualAPI`, this class holds the generated code (`code`) and the language of the code (`language`). + + +#### getProxy Method +- **Functionality**: Creates and returns an instance of `VirtualAPI` using `ChatProxy`, configured with settings from `AppSettingsState` (such as the AI model and temperature for code generation). + + +#### getConfig Method +- **Purpose**: Overrides the `getConfig` method from `SelectionAction`. Currently, it returns an empty string, indicating no additional configuration is required for this action. + + +#### defaultSelection and editSelection Methods +- **Functionality**: These methods determine the default text selection for code generation based on the editor's state. They prioritize the smallest comment block intersecting with the current selection or cursor position as the source of the specification for code generation. + + +#### processSelection Method +- **Core Logic**: Processes the selected text to generate code implementation. It performs several steps: + 1. Determines the human and computer languages from the current context. + 2. Extracts the specification from the selected text or the largest intersecting comment. + 3. Converts the specification into a format suitable for the AI model. + 4. Calls the `implementCode` method of the `VirtualAPI` proxy with the prepared specification and context information. + 5. Inserts the generated code into the editor, following the selected text. + + +#### getPsiClassContextActionParams Method +- **Purpose**: Extracts and prepares parameters related to the PSI (Program Structure Interface) class context, which are required for generating code in the correct context. + + +#### isLanguageSupported Method +- **Functionality**: Determines if the action supports the given computer language, excluding Text and Markdown languages to ensure the action is used for actual code generation. + +This class leverages IntelliJ Platform's infrastructure, such as `runReadAction` for thread-safe operations and `UITools` for UI-related tasks, to integrate AI-powered code generation seamlessly into the development workflow. + +# code\ImplementStubAction.kt + +The `ImplementStubAction` class is designed to facilitate the implementation of stub methods in code by leveraging a virtual API to edit and transform code snippets. This class is part of a larger system aimed at enhancing coding efficiency and automation within an IDE environment. Below is a detailed explanation of its components and functionalities: + + +#### Overview + +- **Package and Imports**: The class is part of the `com.github.simiacryptus.aicoder.actions.code` package and imports various utilities and configurations necessary for its operation, including project settings, language utilities, and proxy services for interacting with an external API. + +- **Class Definition**: `ImplementStubAction` extends `SelectionAction`, indicating it performs an action based on a selected portion of text within the editor and returns a `String` result. + + +#### Inner Interface: `VirtualAPI` + +- **Purpose**: Defines a contract for interacting with a virtual API that can edit code based on specified parameters. +- **Method `editCode`**: Takes a code snippet, an operation type, the computer language of the code, and the human language for instructions. It returns a `ConvertedText` object containing the edited code and its language. + + +#### Class Components + + +##### Private Methods + +- **`getProxy()`**: Creates and returns a proxy instance of `VirtualAPI`, configured with settings from `AppSettingsState` and using `ChatProxy` for communication. + + +##### Overridden Methods + +- **`isLanguageSupported(computerLanguage: ComputerLanguage?)`**: Determines if the given programming language is supported by the action, excluding plain text. +- **`defaultSelection(editorState: EditorState, offset: Int)`**: Calculates and returns the default selection range within the editor, prioritizing code elements. +- **`getConfig(project: Project?)`**: Returns a configuration string for the action, currently implemented to return an empty string. +- **`processSelection(state: SelectionState, config: String?)`**: The core method where the selected code is processed. It extracts the relevant code snippet, determines the smallest intersecting method context, and calls the `editCode` method of the virtual API to implement the stub based on the selected code. + + +#### Logic Flow + +1. **Initialization**: When an instance of `ImplementStubAction` is created, it is ready to interact with the virtual API through a proxy. +2. **Action Invocation**: Upon invoking the action (e.g., through a user command in the IDE), the `processSelection` method is called with the current selection state and configuration. +3. **Selection Processing**: + - Extracts the selected text and additional context (e.g., the smallest intersecting method). + - Cleans up the declaration by removing the intersecting method context and any trailing characters. +4. **API Interaction**: Calls the `editCode` method of the virtual API proxy with the cleaned-up declaration and additional parameters (operation type, languages). +5. **Result Handling**: The edited code returned by the API is then made available for further use, such as replacing the original selection in the editor. + + +#### Configuration and Customization + +- The behavior of `ImplementStubAction` can be influenced by settings in `AppSettingsState`, such as the default chat model and temperature for the API interaction. +- The supported languages and default selections can be adjusted by modifying the `isLanguageSupported` and `defaultSelection` methods, respectively. + +This class exemplifies how modern IDE functionalities can be extended with AI and external APIs to automate and assist in code development tasks. + +# code\RecentCodeEditsAction.kt + +This Kotlin class, `RecentCodeEditsAction`, extends `ActionGroup` and is designed for use within an IntelliJ platform-based IDE. It dynamically generates a list of actions based on the user's recent custom code edits, allowing quick access and execution of these edits. Below is a detailed breakdown of its components and functionality: + + +#### Class Overview +- **Package**: `com.github.simiacryptus.aicoder.actions.code` +- **Imports**: Utilizes various imports from the IntelliJ platform SDK, the project's configuration settings, and utility classes. +- **Class Definition**: `RecentCodeEditsAction` inherits from `ActionGroup`, indicating it is not a singular action but a group of actions. + + +#### Methods + + +##### `update(e: AnActionEvent)` +- **Purpose**: Updates the visibility and enabled state of the action group based on certain conditions. +- **Parameters**: `e: AnActionEvent` - The event that triggered the update. +- **Logic**: + - Calls `isEnabled(e)` to determine if the action group should be enabled and visible. This depends on whether there is a selection in the IDE and if the current language is not plain text. + - Invokes `super.update(e)` to ensure any additional update logic defined in the superclass is executed. + + +##### `getChildren(e: AnActionEvent?): Array` +- **Purpose**: Dynamically generates the child actions based on the user's recent custom code edits. +- **Parameters**: `e: AnActionEvent?` - The event that may trigger this method. It can be `null`. +- **Returns**: An array of `AnAction` objects, each representing a recent custom code edit. +- **Logic**: + - Checks if the event is `null` and returns an empty array if true. + - Retrieves the user's recent commands tagged as "customEdits" from `AppSettingsState`. + - Iterates over these commands, creating a new `CustomEditAction` for each, setting its text to include a numeric identifier and the command itself. + - These actions are collected and returned as an array. + + +##### `isEnabled(e: AnActionEvent): Boolean` +- **Purpose**: Determines if the action group should be enabled based on the current context. +- **Parameters**: `e: AnActionEvent` - The event that triggered the check. +- **Returns**: `Boolean` indicating whether the action group is enabled. +- **Logic**: + - Checks if there is a current selection in the IDE using `UITools.hasSelection(e)`. + - Determines the current programming language and checks if it is not plain text. + - Returns `true` if there is a selection and the language is not plain text, otherwise `false`. + + +#### Configuration and Logic +- The class makes use of `AppSettingsState` to retrieve the user's recent custom code edits, demonstrating how to access and utilize IDE settings. +- It employs a companion object to contain shared logic (`isEnabled`) that determines the action group's availability based on the current context, such as the selected text and programming language. +- The `getChildren` method showcases how to dynamically create and configure actions within the IntelliJ platform, including setting their presentation properties (text, description, icon). + +This class is a practical example of extending IntelliJ platform functionality to provide users with quick access to their recent custom code edits, enhancing productivity and streamlining the development workflow. + +# code\DocAction.kt + +The `DocAction` class extends the `SelectionAction` class to provide functionality for generating documentation comments for selected code blocks within an IDE. This action utilizes a virtual API, represented by the `DocAction_VirtualAPI` interface, to process the selected code and generate the corresponding documentation text. The documentation process involves interaction with a chat model proxy, which is configured to generate documentation in both the computer's programming language and the user's preferred human language. + + +#### Key Components and Logic + + +##### `DocAction_VirtualAPI` Interface +- **Purpose**: Defines the contract for processing code to generate documentation. +- **Key Method**: `processCode(code: String, operation: String, computerLanguage: String, humanLanguage: String)`: Takes the selected code block, the type of documentation operation, the programming language of the code, and the preferred human language for the documentation. It returns an instance of `DocAction_ConvertedText`, which contains the generated documentation text and its language. + + +##### `DocAction_ConvertedText` Class +- **Purpose**: Serves as a container for the generated documentation text and its language. +- **Fields**: + - `text: String?`: The generated documentation text. + - `language: String?`: The language of the generated documentation (e.g., English). + + +##### `proxy: DocAction_VirtualAPI` +- **Purpose**: Lazily initialized proxy for interacting with the chat model to generate documentation. +- **Configuration**: Utilizes `ChatProxy` with settings from `AppSettingsState` (e.g., default chat model, temperature) and retries logic. It also includes an example to guide the model in generating documentation. + + +##### `processSelection(state: SelectionState, config: String?)` +- **Purpose**: Processes the selected code block to generate and prepend documentation. +- **Logic**: + 1. Extracts the selected text from the `SelectionState`. + 2. Converts the selected text into an `IndentedText` object to handle indentation properly. + 3. Calls the `proxy.processCode` method with the indented code block, operation description, programming language, and human language to generate the documentation. + 4. Prepends the generated documentation to the original code block. + + +##### `isLanguageSupported(computerLanguage: ComputerLanguage?)` +- **Purpose**: Determines if the given programming language is supported for documentation generation. +- **Logic**: Checks if the language is not `Text`, has a defined `docStyle`, and the `docStyle` is not blank. + + +##### `editSelection(state: EditorState, start: Int, end: Int)` +- **Purpose**: Adjusts the selection range to include the entire code block for documentation. +- **Logic**: Utilizes `PsiUtil.getCodeElement` to find the code block within the PSI tree and adjusts the selection range to cover the entire block. + + +#### Configuration and Usage +- **Configuration**: The action requires no explicit configuration string (`getConfig` returns an empty string). +- **Usage**: Triggering this action in an IDE with a supported programming language selected will generate and insert documentation comments based on the selected code block. The generated documentation language and style depend on the IDE project settings and the user's preferences set in `AppSettingsState`. + +This class demonstrates an innovative approach to integrating AI-based documentation generation within development environments, enhancing developer productivity by automating the creation of descriptive comments for code blocks. + +# code\PasteAction.kt + + +#### Class Overview + +The `PasteAction` class extends the `SelectionAction` class, specifically designed for handling paste actions within the context of the AI Coder plugin. This action facilitates the conversion of clipboard content into a different programming language using an external API, represented by the `VirtualAPI` interface. The conversion process is tailored to the target language of the current selection state. + + +#### Key Components + + +##### VirtualAPI Interface + +- **Purpose**: Serves as a contract for implementing the conversion of text from one programming language to another. +- **Methods**: + - `convert(text: String, from_language: String, to_language: String)`: Converts the given text from the source language to the target language. Returns an instance of `ConvertedText`. +- **Inner Class**: `ConvertedText` holds the result of the conversion, including the converted code (`code`) and the language of the converted code (`language`). + + +##### Overridden Methods + +- `getConfig(project: Project?)`: Returns a configuration string for the action. In this implementation, it returns an empty string as the configuration is not utilized. + +- `processSelection(state: SelectionState, config: String?)`: Processes the selected text for conversion. It uses the `ChatProxy` to communicate with the external API, passing the clipboard content, auto-detecting the source language, and specifying the target language based on the current selection state. Returns the converted code or an empty string if conversion fails. + +- `isLanguageSupported(computerLanguage: ComputerLanguage?)`: Determines if the paste action supports the specified programming language. Returns `false` for `ComputerLanguage.Text` and `true` for all other languages. + +- `isEnabled(event: AnActionEvent)`: Checks if the paste action should be enabled based on the presence of supported content in the clipboard. Returns `true` if the clipboard contains text data; otherwise, returns `false`. + + +#### Clipboard Handling + +- **Clipboard Content Check (`hasClipboard`)**: Checks if the system clipboard contains data that can be interpreted as text. Supports both plain text and Unicode text flavors. + +- **Retrieving Clipboard Content (`getClipboard`)**: Retrieves the content from the system clipboard if it supports the required data flavors (plain text or Unicode text). Returns the clipboard content as an `Any?` type, or `null` if the content is not supported. + + +#### Usage + +This class is designed to be used within an IDE environment where the AI Coder plugin is installed. It enhances the development experience by allowing developers to easily convert and paste code snippets from one programming language to another, directly from the clipboard, with minimal configuration required from the user's end. + +# code\RenameVariablesAction.kt + + +#### RenameVariablesAction Class Documentation + +The `RenameVariablesAction` class extends the `SelectionAction` class, specifically designed for renaming variables within a selected piece of code in an IDE environment. This action utilizes an external API for suggesting new variable names that are more descriptive or appropriate according to the context of the code and the conventions of the programming language. + + +##### Key Components + +- **RenameAPI Interface**: Defines the contract for the external service that suggests new names for variables. It includes a single method, `suggestRenames`, which takes the code snippet, the computer language of the code, and the human language for the suggestions. It returns a `SuggestionResponse` containing a list of suggested renames. + +- **SuggestionResponse and Suggestion Classes**: Nested within the `RenameAPI`, these classes are used to encapsulate the response from the rename suggestion API. `SuggestionResponse` contains a list of `Suggestion` objects, each of which holds an `originalName` and a `suggestedName`. + +- **proxy Property**: A lazy-initialized property that creates a proxy to the rename suggestion API using the `ChatProxy` class. It is configured with settings from `AppSettingsState`, such as the default chat model and temperature for generating suggestions. + + +##### Methods + +- **getConfig**: This method is overridden from the `SelectionAction` class but is not utilized in this implementation, returning an empty string. + +- **processSelection**: The core logic of the action, which processes the selected text to generate and apply rename suggestions. It performs the following steps: + 1. Calls the rename suggestion API through the `proxy` to get suggestions for the selected text. + 2. Filters out suggestions where either the original name or the suggested name is null. + 3. Presents the user with a dialog to choose which suggestions to apply. + 4. Applies the selected suggestions to the selected text and returns the modified text. + +- **choose**: Presents a dialog with checkboxes for each rename suggestion, allowing the user to select which variables to rename. Returns a set of selected original variable names. + +- **isLanguageSupported**: Checks if the action supports the given computer language. It returns `false` for plain text (`ComputerLanguage.Text`) and `true` for all other languages. + + +##### Configuration and Logic + +- The rename suggestions are generated based on the context of the selected code snippet, the programming language of the code (`state.language`), and the user's preferred human language for suggestions (`AppSettingsState.instance.humanLanguage`). + +- The `ChatProxy` used for the `proxy` property is configured with parameters from `AppSettingsState`, such as the model and temperature, which influence how the suggestions are generated. + +- The `processSelection` method uses `UITools.run` to execute the suggestion fetching and application on the UI thread, ensuring that the IDE remains responsive. + +- The `choose` method utilizes `UITools.showCheckboxDialog` to present the user with a choice of which variable names to rename, enhancing the interactivity of the action. + +This class demonstrates a sophisticated integration of external AI-based services for code refactoring tasks within an IDE, leveraging user settings and preferences to tailor the suggestions. + +# dev\PrintTreeAction.kt + + +#### Class Documentation: PrintTreeAction + + +##### Overview +The `PrintTreeAction` class extends the functionality of `BaseAction` to provide a specific action within the IntelliJ IDE. This action allows developers to print the tree structure of a PsiFile, which is particularly useful for understanding the organization and hierarchy of elements within a file. The action is contingent upon a specific setting (`devActions`) being enabled in the application's settings. + + +##### Usage +To utilize the `PrintTreeAction`, follow these steps: +1. Ensure that the `devActions` setting is enabled in the application's settings. This setting is crucial for the action to be available. +2. Open the file within IntelliJ for which you wish to print the tree structure. +3. Access the "PrintTreeAction" from the editor's context menu. +4. Upon selection, the tree structure of the currently opened file will be printed to the log. + + +##### Implementation Details + + +###### Methods + +- `handle(e: AnActionEvent)`: This method is overridden from the `BaseAction` class. It is the core function that executes the action's primary operation. When invoked, it retrieves the largest contained entity within the current file using `PsiUtil.getLargestContainedEntity(e)` and prints its tree structure to the log using `PsiUtil.printTree(...)`. + +- `isEnabled(event: AnActionEvent)`: Also overridden from `BaseAction`, this method determines whether the `PrintTreeAction` is available to the user. It checks the `AppSettingsState.instance.devActions` configuration to see if developer actions are enabled. The action is only enabled and visible in the context menu if this setting returns `true`. + + +###### Configuration +- The action's availability is controlled by the `devActions` setting found in `AppSettingsState`. This setting must be enabled for the action to be accessible. + + +###### Logging +- The class utilizes SLF4J for logging purposes, with a private static logger instantiated specifically for `PrintTreeAction`. This logger is used to output the tree structure of the PsiFile to the log, facilitating debugging and analysis by developers. + + +##### Conclusion +The `PrintTreeAction` class is a developer-oriented feature within the IntelliJ plugin that leverages the application's settings and PSI utilities to provide insights into the structure of PsiFiles. By printing the tree structure to the log, it aids developers in understanding and navigating the complexity of their codebase. + +# FileContextAction.kt + +This Kotlin code defines an abstract class `FileContextAction` that extends `BaseAction`, designed to be a part of an IntelliJ IDEA plugin. The class is intended to provide a framework for actions that operate on files or folders within the IDE, allowing for the processing of selected files or folders based on specific configurations. Below is a detailed explanation of the key components related to prompt text, configuration, and related logic within the class. + + +#### Class Definition + +- `FileContextAction`: An abstract class that takes a generic type `T`, representing the configuration type for the action. It requires two boolean parameters, `supportsFiles` and `supportsFolders`, to indicate whether the action supports file and/or folder operations. + + +#### Inner Data Class + +- `SelectionState`: A data class that holds the currently selected file and the project root directory as `File` objects. This class is used to pass the selection context to the `processSelection` method. + + +#### Abstract Method + +- `processSelection(state: SelectionState, config: T?): Array`: An abstract method that subclasses must implement. It processes the selected file or folder based on the provided configuration of type `T` and returns an array of `File` objects that result from this processing. + + +#### Configuration Method + +- `getConfig(project: Project?, e: AnActionEvent): T?`: An open method that returns a configuration object of type `T` for the action. By default, it returns `null`, but subclasses can override this method to provide specific configurations based on the project and the action event. + + +#### Action Handling + +- The `handle(e: AnActionEvent)` method is the entry point for the action. It retrieves the configuration using `getConfig`, determines the selected file or folder, and then processes the selection in a separate thread. It uses utility methods from `UITools` for task management and file operations within the IDE. + + +#### Utility Methods + +- `isEnabled(event: AnActionEvent): Boolean`: Overrides the `isEnabled` method to determine if the action should be enabled based on the current selection (file or folder) and the `isDevAction` flag in conjunction with the application settings. + +- `open(project: Project, outputPath: Path)`: A companion object method that attempts to open a file in the IDE editor. If the file is not immediately available, it schedules retries using a scheduled executor service. + + +#### Logging and Error Handling + +- The class includes a `log` object for logging purposes and implements error handling in the `handle` method, logging any exceptions that occur during the processing of the selection. + +This class serves as a foundation for creating IntelliJ IDEA plugin actions that operate on files or folders, providing mechanisms for configuration, selection processing, and integration with the IDE's file editor. Implementers are required to define the specific processing logic and configuration by extending this class and overriding the abstract and open methods. + +# dev\AppServer.kt + + +#### Class Overview + +The `AppServer` class is part of the `com.github.simiacryptus.aicoder.actions.dev` package and is designed to manage a web server within a development environment, specifically tailored for applications that require real-time communication, such as chat applications. It leverages the Jetty server framework to dynamically add and manage web application contexts, facilitating the deployment of chat services. + + +#### Key Components and Functionality + +- **Initialization**: The server is initialized with a local name and port, along with an optional `Project` instance. This setup allows the server to bind to a specific address and listen for incoming connections. + +- **Server Management**: At its core, the class manages a Jetty `Server` instance, which is lazily instantiated. The server's handler is set to a `ContextHandlerCollection`, which aggregates multiple web application contexts. + +- **Dynamic Context Handling**: The class supports the dynamic addition of web application contexts through the `addApp` method. This method allows for the registration of `ChatServer` instances under specific paths, facilitating the deployment of multiple chat applications on the same server. + +- **WebApp Context Configuration**: For each chat application, a new `WebAppContext` is created and configured. This includes setting up WebSocket support, defining the base resource, class loader, context path, and welcome files. The chat server's specific configuration is also applied to the context. + +- **Server Lifecycle Management**: The class includes mechanisms to start and stop the server, as well as to monitor its running state. A separate thread is used to track the server's progress and handle its lifecycle based on user actions or system events. + +- **Singleton Pattern**: The `AppServer` class implements a singleton pattern through its companion object. This ensures that only one instance of the server is active at any given time, providing a centralized point of control. The `getServer` method is used to obtain the current instance or create a new one if necessary, while the `stop` method facilitates server shutdown. + + +#### Usage + +1. **Initialization**: Create or obtain an instance of the `AppServer` using the `getServer` method, providing the necessary configuration parameters. + +2. **Adding Applications**: Use the `addApp` method to dynamically add chat applications to the server. Specify the application's path and provide an instance of `ChatServer` configured for the application. + +3. **Server Control**: Start the server using the `start` method. Monitor its state and manage its lifecycle as needed. Use the `stop` method to shut down the server when it is no longer needed. + + +#### Conclusion + +The `AppServer` class provides a flexible and efficient way to manage a web server for real-time communication applications within a development environment. Its ability to dynamically add and configure web application contexts makes it particularly suited for scenarios where multiple chat services need to be deployed and managed concurrently. + +# dev\InternalCoderAction.kt + +The `InternalCoderAction` class is part of a plugin designed to integrate an internal coding agent into the IntelliJ IDE. This class extends `BaseAction` and is responsible for initializing and managing a coding session within the IDE. The action is triggered by user interaction, such as clicking a menu item or a button. Below is a detailed explanation of the key components and logic within the `InternalCoderAction` class. + + +#### Key Components + +- **Path Configuration**: The `path` variable is set to `"/internalCoder"`, which specifies the endpoint for the internal coding agent within the application server. + +- **Action Handling (`handle` method)**: This method is invoked when the action is triggered. It performs several key operations: + - **Session Initialization**: A new global session ID is generated using `StorageInterface.newGlobalID()`. + - **Server and Application Initialization**: Retrieves the application server instance for the current project and initializes the coding application on the server with the specified path. + - **Socket Manager**: A new session is created for the coding application, and a socket manager is associated with this session. + - **Symbol Collection**: Collects various symbols from the action event, such as the editor, file, project, and others, and stores them in a map for later use. + - **Coding Agent Initialization**: Initializes a `CodingAgent` with the collected symbols, session information, and other configurations. This agent is responsible for handling coding tasks. + - **Browser Navigation**: Opens the user's default browser and navigates to the URL of the coding session after a brief delay. + +- **Action Availability (`isEnabled` method)**: Determines whether the action should be enabled or disabled based on the application's settings. Specifically, it checks if the development actions are enabled in the `AppSettingsState`. + +- **Application Initialization (`initApp` method)**: A helper method that initializes the coding application on the server if it hasn't been initialized already. It creates a new `ApplicationServer` instance with a specific application name and path, and overrides the `userMessage` method to handle messages from users. + + +#### Configuration and Logic + +- **Dynamic Symbol Handling**: The action dynamically collects context information (symbols) from the IDE and passes it to the coding agent. This allows the agent to operate with a rich context, enhancing its coding suggestions and operations. + +- **Session Management**: Each coding session is uniquely identified by a session ID, allowing multiple coding sessions to be managed independently. + +- **Application Server Integration**: The action integrates closely with the application server, adding a new application for the coding agent and handling user messages through the server's infrastructure. + +- **User Interface Interaction**: The action interacts with the user's desktop environment to open a browser window, directing the user to the coding session's UI. This provides a seamless transition from the IDE to the coding agent's interface. + +- **Development Mode Check**: The action's availability is contingent on the development mode setting, ensuring that it is only accessible when appropriate for the development environment. + +This class exemplifies how to extend IDE functionality with external services (like a coding agent) by integrating with the IDE's action system, managing sessions, and interacting with application servers and user interfaces. + +# generic\GenerateRelatedFileAction.kt + + +#### CreateFileFromTemplateAction Class Documentation + +The `CreateFileFromTemplateAction` class is designed to facilitate the creation of new files within a project, based on a given directive and the content of an existing file. This action is context-sensitive, meaning it is only enabled when a non-directory file is selected in the IDE. The class extends `FileContextAction` and is tailored for use within IntelliJ-based IDEs. + + +##### Key Components + +- **isEnabled(event: AnActionEvent): Boolean** + Determines if the action should be enabled based on the current context. It checks if the selected item is not a directory. + +- **SettingsUI Class** + Defines the UI component for collecting user input. It includes a JTextArea for entering directives for file creation. + +- **UserSettings Class** + Holds the user-provided settings, specifically the directive for file creation. + +- **Settings Class** + Encapsulates the settings necessary for file creation, including the `UserSettings` and the current `Project`. + +- **getConfig(project: Project?, e: AnActionEvent): Settings** + Configures and returns the settings for file creation, including collecting user input through a dialog. + +- **processSelection(state: SelectionState, config: Settings?): Array** + Main logic for processing the selected file and creating a new file based on the provided directive. It involves generating the new file's content and path, ensuring no naming conflicts, and writing the content to the new file. + +- **generateFile(baseFile: ProjectFile, directive: String): ProjectFile** + Generates the new file's content and path based on a given directive and the content of an existing file. It utilizes an AI model to combine the directive with the base file's content to produce the output. + +- **open(project: Project, outputPath: Path)** + Opens the newly created file in the editor, ensuring the file is visible and accessible to the user. + +- **getModuleRootForFile(file: File): File** + Utility function to find the root directory of the module to which the given file belongs, identified by the presence of a `.git` directory. + + +##### Usage + +This action is intended to be triggered from the IDE's context menu when a file is selected. Upon activation, it presents a dialog for the user to enter a directive for the new file's creation. The action then processes the selected file and the directive to generate a new file, ensuring it does not overwrite existing files. The new file is then opened in the editor for immediate access. + + +##### Implementation Details + +- The action leverages the IntelliJ Platform SDK for UI components and file manipulation. +- It uses an AI model (via `ApiModel.ChatRequest`) to generate the new file's content based on natural language instructions and the content of an existing file. +- The action ensures compatibility with the project's file structure and adheres to best practices for file creation within an IDE environment. + +This class is a part of the `com.github.simiacryptus.aicoder.actions.generic` package and requires several dependencies, including the IntelliJ Platform SDK, Apache Commons IO, and the `com.simiacryptus.jopenai` package for AI model interaction. + +# generic\AppendTextWithChatAction.kt + + +#### Class Documentation: `AppendTextWithChatAction` + +`AppendTextWithChatAction` is a specialized action class that extends the functionality of `SelectionAction`. It is designed to append text to the end of a user's selected text within an IntelliJ IDEA project environment. This class leverages the OpenAI API to generate the text that will be appended, using a model specified in the application's settings. + + +##### Configuration + +The `getConfig` method is designed to fetch configuration settings for the action, but in the current implementation, it returns an empty string. This method can be overridden to provide specific configuration strings based on the project context if needed. + + +##### Process Selection + +The core functionality of the `AppendTextWithChatAction` class is encapsulated in the `processSelection` method. This method takes a `SelectionState` and a configuration string as inputs and returns a string that represents the original selected text with additional text appended to it. The method performs the following steps: + +1. **Fetch Settings**: It retrieves the current application settings using `AppSettingsState.instance`, which includes the default chat model and temperature settings for generating text. + +2. **Prepare Chat Request**: It constructs a `ChatRequest` object with the model specified in the settings and a temperature value. The request includes two messages: + - A system message indicating the action to be performed ("Append text to the end of the user's prompt"). + - A user message containing the text currently selected by the user. + +3. **API Call**: It makes a call to the OpenAI API using the `api.chat` method, passing the prepared `ChatRequest` and the model specified in the settings. + +4. **Append Text**: It retrieves the response from the API and appends the generated text to the original selected text. If the generated text starts with the original selected text, it ensures that the original text is not duplicated in the appended result. + + +##### Usage + +This class is intended to be used within the context of an IntelliJ IDEA plugin, where it can be invoked to append generated text to a user's selected text in the editor. The actual appending logic is dependent on the response from the OpenAI API, making it versatile for various text augmentation tasks. + + +#### Important Considerations + +- The `processSelection` method relies on the OpenAI API, and as such, requires a valid API key and network connectivity. +- The method ensures that the original selected text is not duplicated in the appended result, which is a crucial detail for maintaining text integrity. +- The current implementation does not utilize the `config` parameter in `processSelection`, but it is available for future enhancements or custom configurations. + +This class demonstrates a practical application of AI in enhancing developer tools, specifically in automating text-related tasks within an IDE. + +# generic\VoiceToTextAction.kt + +The `VoiceToTextAction` class is designed to facilitate speech-to-text functionality within an IDE, leveraging audio recording and processing to convert spoken words into text. This process involves capturing audio, processing it for clarity, and then converting the audio into text which is inserted at the current caret position or replaces the selected text in the editor. A significant part of this functionality revolves around the management and use of a "prompt" text, which is crucial for understanding and documenting how the dictation action operates. + + +#### Prompt Text Configuration and Logic + +The prompt text plays a critical role in the speech-to-text conversion process, especially in the context of continuous dictation where the context of previously dictated text can significantly enhance the accuracy of the transcription. The `DictationPump` inner class is primarily responsible for handling the audio buffer and converting its contents into text, with the prompt text being a key component of this process. + + +##### Initialization and Updates + +- **Initialization**: The prompt text is initialized in the `DictationPump` constructor, where it can be set to the text currently selected by the user (if any). This allows the speech-to-text API to have context right from the start, potentially improving the accuracy of the transcription. + +- **Updates**: After each successful transcription, the prompt text is updated with the most recent transcription result. This is achieved by appending the new text to the existing prompt, splitting the prompt into individual words, and then keeping only the last 32 words. This updated prompt is then used for the next transcription request, ensuring that the context is maintained throughout the dictation session. + + +##### Usage + +- The prompt text is used as part of the transcription request to the speech-to-text API (`api.transcription(recordAudio, prompt)`). Providing this context allows the API to better understand the intended meaning of the spoken words, especially in cases where the dictation involves complex or domain-specific language. + + +#### Closing Remarks + +The management of the prompt text within the `VoiceToTextAction` class showcases a thoughtful approach to enhancing the accuracy and usability of speech-to-text functionality in an IDE setting. By maintaining and updating a context-aware prompt, the implementation ensures that users can enjoy a more seamless and accurate dictation experience, even during extended dictation sessions. This feature underscores the importance of context in natural language processing applications and demonstrates a practical application of such principles in software development tools. + +# generic\CodeChatAction.kt + +The `CodeChatAction` class is designed to facilitate a code chat feature within an IDE, leveraging various components for session management, language detection, and web socket communication. This class extends `BaseAction`, indicating it is an action that can be triggered within the IDE environment. Below is a detailed breakdown of its functionality, configuration, and related logic: + + +#### Overview + +- **Purpose**: To open a code chat session for the currently selected code or the entire document if no selection is made. +- **Key Features**: + - Detects the programming language of the current document. + - Opens a web-based chat interface in the default browser, specifically designed for discussing code. + - Utilizes web sockets for real-time communication. + - Stores session information for continuity and reference. + + +#### Configuration and Properties + +- **`path`**: A string representing the endpoint for the code chat application. It is set to `"/codeChat"` and used to construct the URL for the web interface. +- **`root`**: A file path that points to the storage location for code chat data. It is derived from the plugin's home directory combined with `"code_chat"`. + + +#### Key Methods and Logic + + +##### `handle(e: AnActionEvent)` + +- **Parameters**: Receives an `AnActionEvent` object which provides context about the action event, including access to the current editor and project. +- **Functionality**: + - Retrieves the current editor and aborts if not available. + - Generates a new global session ID. + - Determines the programming language of the current document. + - Extracts the filename and the selected text (or entire text if no selection is made) from the editor. + - Initializes a `CodeChatSocketManager` and stores it in a session-specific map for managing web socket communication. + - Sets up a `ChatServer` instance for the session and opens the chat interface in the default web browser. + + +##### `isEnabled(event: AnActionEvent)` + +- Always returns `true`, indicating that this action is always enabled. + + +##### `initApp(server: AppServer, path: String)` + +- **Purpose**: To initialize the chat server application if it hasn't been already. +- **Parameters**: + - `server`: An instance of `AppServer` which manages server-side applications. + - `path`: The endpoint path for the code chat application. +- **Functionality**: + - Checks if the application is already registered with the server. If so, it returns the existing instance. + - If not registered, it creates a new `ApplicationServer` instance specifically for code chat, configuring it with properties like `applicationName`, `singleInput`, and `stickyInput`. + - Registers the new chat server application with the `AppServer`. + + +#### Logging + +- Utilizes SLF4J for logging, particularly for capturing any issues that occur when attempting to open the web browser to display the chat interface. + + +#### Session Management + +- Manages sessions through a combination of `StorageInterface.newGlobalID()` for session ID generation and a custom map (`agents`) for storing `SocketManager` instances associated with each session. + + +#### Conclusion + +The `CodeChatAction` class is a comprehensive solution for integrating a code-focused chat feature within an IDE. It handles the initialization of necessary components, manages sessions, and ensures seamless communication between the IDE and the web-based chat interface. + +# generic\MultiStepPatchAction.kt + +The `MultiStepPatchAction` class is part of a larger system designed to automate development tasks within a software project. It leverages AI models to interpret user requests, generate action plans, and apply changes to the codebase. This documentation focuses on the prompt text, configuration, and related logic within the `MultiStepPatchAction` class. + + +#### Overview + +The `MultiStepPatchAction` class initiates an automated development assistant that interacts with the user through a web interface. It creates a session for each user request, processes the input, and utilizes AI agents to generate and execute a series of development tasks based on the user's instructions. + + +#### Key Components + + +##### 1. AutoDevApp + +- **Purpose**: Serves as the main application server for handling user messages and initiating the AI-driven development process. +- **Configuration**: + - `applicationName`: The name of the application, defaulting to "Auto Dev Assistant v1.1". + - `symbols`: A map of symbols used within the application, initially empty. + - `temperature`: Controls the creativity of the AI responses. A lower value (e.g., 0.1) results in more predictable outputs. + - `event`: The `AnActionEvent` triggering the action. + + +##### 2. AutoDevAgent + +- **Purpose**: Acts as the core agent system for processing user messages and executing development tasks. +- **Actor Types**: + - `DesignActor`: Translates user directives into an actionable plan, breaking down the request into a list of simple tasks. + - `TaskCodingActor`: Implements the changes to the codebase as described in the task list, using code patches in diff format. +- **Configuration**: + - `api`: The API interface for interacting with AI models. + - `model`: The AI model used for generating responses, with a default of `ChatModels.GPT35Turbo`. + - `tools`: A list of tools or technologies relevant to the task at hand, initially empty. + - `actorMap`: Maps actor types to their corresponding actor implementations. + + +##### 3. Prompts + +- **DesignActor Prompt**: + - Asks the AI to translate user directives into an action plan, specifying files to be modified and describing the changes. +- **TaskCodingActor Prompt**: + - Requests the AI to implement code changes based on the task list, using diff format for code patches. It includes instructions for formatting the response and an example. + + +#### Logic Flow + +1. **Initialization**: Upon handling an `AnActionEvent`, the `MultiStepPatchAction` class initializes a session and sets up the `AutoDevApp`. +2. **User Interaction**: The `AutoDevApp` listens for user messages and, upon receiving one, invokes the `AutoDevAgent`. +3. **Task Generation**: The `AutoDevAgent` uses the `DesignActor` to break down the user's request into a list of tasks. +4. **Task Execution**: For each task, the `TaskCodingActor` generates code patches to implement the required changes. +5. **Output**: The changes are presented to the user, who can review and apply them to the codebase. + + +#### Conclusion + +The `MultiStepPatchAction` class and its components represent a sophisticated system for automating development tasks using AI. By interpreting user requests, generating actionable plans, and executing code changes, it aims to streamline the development process and reduce manual effort. + +# generic\CreateFileFromDescriptionAction.kt + +This Kotlin class, `CreateFileFromDescriptionAction`, is part of a larger system designed to automate file creation within a project structure based on natural language directives. It extends `FileContextAction` with specific settings for creating files. The action utilizes an AI model to interpret directives and generate the necessary file content and path. Below is a detailed breakdown of its components and functionality: + + +#### Class Overview + +- **ProjectFile**: A simple data class holding information about a file to be created, including its path and the code content. +- **SettingsUI**: Defines the user interface for configuring the action. It includes a text area for entering the directive that guides the file creation process. +- **Settings**: Holds the configuration settings for the action, primarily the directive as a string. +- **processSelection**: The core method that processes the selected file or directory and generates a new file based on the provided directive and the context of the selection. + + +#### Configuration and Logic + +- **Directive**: A key component of the `Settings` and `SettingsUI` classes, representing the natural language instructions for generating the new file. This directive is used by the AI model to understand what file needs to be created and what its contents should be. +- **generateFile**: A private method that takes a base path and a directive as inputs. It communicates with an AI model to generate the path and content for the new file based on the directive. The method constructs a `ChatRequest` to the AI, including the directive and contextual information about the desired file location. The AI's response is parsed to extract the file path and content. + + +#### AI Model Interaction + +- The interaction with the AI model is facilitated through the `generateFile` method, which constructs a `ChatRequest` object. This request includes: + - The model name and temperature settings from `AppSettingsState`. + - A system message that sets the context for the AI, explaining the task of interpreting natural language to create a file. + - A user message containing the directive and additional context about the file location. + +- The AI's response is expected to include a header line indicating the file path, followed by the file content. The method parses this response to extract the necessary information and create a `ProjectFile` object. + + +#### File Creation Logic + +- The `processSelection` method determines the appropriate path for the new file based on the current selection and the AI-generated path. It handles potential conflicts by checking for existing files and, if necessary, generating a unique filename to avoid overwriting. +- Once the final path is determined, the method writes the AI-generated code to the new file and returns the file as part of an array, indicating successful creation. + +This class demonstrates a sophisticated integration of AI capabilities into a development environment, leveraging natural language processing to automate routine tasks like file creation based on user-provided directives. + +# generic\LineFilterChatAction.kt + +The `LineFilterChatAction` class is designed to facilitate a unique interaction within an IDE, where it enables users to engage in a chat session focused on discussing and understanding specific segments of code. This functionality is particularly useful for developers seeking assistance or clarification on code snippets. Below is a detailed explanation of the key components related to the prompt text, configuration, and the closely related logic within the `LineFilterChatAction` class. + + +#### Prompt Text Configuration + +The class configures two main types of prompts for the chat session: the `userInterfacePrompt` and the `systemPrompt`. These prompts are designed to guide the interaction between the user and the AI within the chat environment. + +- **`userInterfacePrompt`**: This prompt is displayed to the user and includes the filename, the programming language of the code, and the code snippet itself. It is formatted using markdown to enhance readability. The purpose of this prompt is to present the code in question clearly and concisely to the user. + +- **`systemPrompt`**: This prompt is designed for the AI's understanding. It informs the AI that its role is to assist with coding questions related to the provided code snippet. The prompt includes the filename, the programming language, and the code snippet with line numbers added for reference. This detailed prompt enables the AI to reference specific lines in its responses, facilitating a more focused and helpful discussion. + + +#### Logic for Prompt Preparation + +The preparation of the prompts involves several steps: + +1. **Retrieving and Formatting Code**: The action retrieves the code either from the selected text in the editor or the entire document if no text is selected. It then formats the code by adding line numbers, which are crucial for the AI to reference specific lines in its responses. + +2. **Determining Language and Filename**: The action identifies the programming language of the code and the filename. This information is essential for formatting the `userInterfacePrompt` and `systemPrompt` correctly and ensuring that the AI understands the context of the discussion. + +3. **Creating ChatSocketManager Instance**: An instance of `ChatSocketManager` is created with the prepared prompts. This instance is responsible for managing the chat session, including sending prompts to the AI and rendering the AI's responses. The `renderResponse` method within this instance is particularly noteworthy as it processes the AI's responses, translating line references into actual code lines or keeping the original response text as appropriate. + + +#### Chat Session Initialization + +After configuring the prompts and related logic, the action initiates a chat session by: + +1. **Creating a New Session**: A new session is created with a unique session ID. This session is associated with the `ChatSocketManager` instance prepared earlier. + +2. **Launching the Chat Interface**: The action opens a web browser to the chat interface, allowing the user to start interacting with the AI immediately. This step is performed in a separate thread to avoid blocking the main application thread. + + +#### Summary + +The `LineFilterChatAction` class leverages detailed prompt configuration and sophisticated logic to facilitate an interactive chat session focused on code discussion. By providing clear prompts and managing the chat session efficiently, it offers a valuable tool for developers seeking assistance with their code. + +# generic\GenerateDocumentationAction.kt + +The `GenerateDocumentationAction` class is designed to automate the process of compiling documentation from selected files within an IntelliJ IDEA project. It leverages the OpenAI API to transform the content of these files into a more structured and user-friendly documentation format. Below is a detailed explanation of the key components and logic related to the configuration and processing of this action. + + +#### Configuration + + +##### SettingsUI Class +- **Transformation Message (`transformationMessage`)**: A `JTextArea` component that allows the user to input a custom message or instructions that will guide the transformation of the file content into documentation. This message is passed to the OpenAI API as part of the request. +- **Output Filename (`outputFilename`)**: Another `JTextArea` component where the user specifies the name of the output file that will contain the compiled documentation. The default value is `compiled_documentation.md`. +- **Files to Process (`filesToProcessScrollPane`)**: A `JBScrollPane` that contains a `CheckBoxList` displaying all the files eligible for processing. The user can select or deselect files from this list. + + +##### UserSettings Class +Holds the user-configurable settings: +- `transformationMessage`: Stores the transformation message input by the user. +- `outputFilename`: Stores the output filename specified by the user. +- `filesToProcess`: A list of `Path` objects representing the files selected by the user for processing. + + +##### Settings Class +Encapsulates the `UserSettings` and the current `Project` instance. It is used to pass these settings to the processing logic. + + +#### Processing Logic + + +##### isEnabled Method +Determines if the action should be enabled based on the current context. It checks if the selected item is not a directory, ensuring that the action is only available for file selections. + + +##### getConfig Method +Responsible for displaying the configuration UI to the user and collecting the settings. It walks through the file system starting from the selected folder, listing all regular files (excluding directories) and populating the `filesToProcess` list. The method then displays a dialog where the user can adjust settings and select files for processing. + + +##### processSelection Method +Executes the main logic for compiling documentation. It performs the following steps: +1. Determines the output path for the compiled documentation, creating a new file if one already exists with the specified name. +2. Initializes an executor service for parallel processing. +3. Partitions the files into those selected for processing and others. +4. For each selected file, reads its content, sends it to the OpenAI API along with the transformation message, and appends the transformed content to the markdown output. +5. Writes the compiled markdown content to the output file. +6. Opens the output file in the IDE. + + +##### transformContent Method +Sends the file content and transformation message to the OpenAI API, requesting a transformation based on natural language instructions and the provided code example. It constructs a `ChatRequest` with the file content and transformation message as user messages, and the instruction to document code as a system message. The response is then used to generate the documentation content. + + +##### open Method (Companion Object) +A utility method that attempts to open the compiled documentation file in the IDE. It repeatedly checks if the file exists and is not already open, attempting to open it and scheduling retries with a delay if necessary. + +This class and its methods demonstrate a sophisticated integration with the IntelliJ Platform SDK, leveraging both the IDE's UI components for configuration and external APIs for content transformation. + +# generic\DiffChatAction.kt + +The `DiffChatAction` class is part of a larger application designed to facilitate code discussions and reviews directly within an IDE (Integrated Development Environment). This class specifically handles the initiation of a "diff chat" session, where users can discuss changes to code in a chat interface that supports diff formatting. Below is a detailed explanation of the key components related to the prompt text, configuration, and the logic closely associated with these elements. + + +#### Key Components + + +##### 1. System Prompt Configuration +The system prompt is a crucial part of the user interaction within the diff chat. It instructs users on how to format their code patches using the diff format within the chat interface. The prompt is defined in the `systemPrompt` property of the anonymous `CodeChatSocketManager` class instance created within the `handle` method. The prompt text encourages users to provide code patches in diff format, using `+` for line additions and `-` for line deletions, and to include sufficient context around changes. + +```kotlin +override val systemPrompt: String + get() = super.systemPrompt + """ + Provide code patches in diff format within ```diff code blocks. + The diff format should use + for line additions, - for line deletions. + The diff should include sufficient context before every change to identify the location. + """.trimIndent() +``` + + +##### 2. Response Rendering +The `renderResponse` method is responsible for rendering the chatbot's response. It first processes the response to add links that allow applying the suggested diffs directly to the code. This is achieved through the `addApplyDiffLinks` utility function, which takes the original code, the response containing the diffs, and a callback function to apply the new code. The processed response is then converted to HTML using the `renderMarkdown` function, ensuring that the chat interface can display it properly. + +```kotlin +override fun renderResponse(response: String): String { + val withLinks = addApplyDiffLinks(rawText, response) { newCode -> + WriteCommandAction.runWriteCommandAction(e.project) { + document.replaceString(selectionStart, selectionEnd, newCode) + } + } + val html = renderMarkdown(withLinks) + return """
$html
""" +} +``` + + +##### 3. Chat Session Initialization +The chat session is initialized in the `handle` method, where a new `CodeChatSocketManager` instance is created and associated with a session ID. This setup involves configuring the session with the selected code (or the entire document if no selection is made), the programming language, and other relevant details. The session is then registered with an `AppServer` instance, which manages the web interface for the chat. + +```kotlin +val server = AppServer.getServer(e.project) +val app = initApp(server, path) +app.sessions[session] = app.newSession(null, session) +``` + + +##### 4. Browser Interaction +After initializing the chat session, the class attempts to open the user's default web browser to the chat interface using the `Desktop.getDesktop().browse` method. This step is performed in a separate thread to avoid blocking the main application thread. + +```kotlin +Thread { + Thread.sleep(500) + try { + Desktop.getDesktop().browse(server.server.uri.resolve("$path/#$session")) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } +}.start() +``` + + +#### Conclusion +The `DiffChatAction` class integrates with an IDE to provide a unique interface for discussing code changes using diff formatting. It leverages Kotlin's capabilities to interact with the IDE's editor, manage sessions, and render interactive content in a web interface. This class is a part of a larger system designed to enhance the code review and collaboration process directly within the development environment. + +# generic\RedoLast.kt + + +#### RedoLast Action + +The `RedoLast` class is a custom IntelliJ action designed to allow users to redo the last AI Coder action they executed within the IntelliJ editor. This functionality is particularly useful for developers working with AI Coder, enabling them to quickly revert and reapply changes made by the AI. + + +##### Configuration and Usage + +To utilize the `RedoLast` action, users must first be within the IntelliJ editor where they previously performed an AI Coder action. The action can be triggered by selecting "RedoLast" from the editor's context menu. This initiates the redo operation for the last action executed in that specific editor session. + + +##### Implementation Details + +The `RedoLast` class extends `BaseAction`, inheriting its basic action handling capabilities. The core functionality is implemented within two overridden methods: + +- `handle(e: AnActionEvent)`: This method is responsible for executing the redo operation. It retrieves the current editor's document from the event object `e` using `e.getRequiredData(CommonDataKeys.EDITOR).document`. It then checks if there is a retry operation available for this document in the `retry` map. If available, it executes the `run()` method of the corresponding retry operation. + +- `isEnabled(event: AnActionEvent)`: This method determines whether the RedoLast action should be enabled or disabled in the context menu. It checks if there is a retry operation available for the current editor's document in the `retry` map. The action is enabled if a retry operation exists; otherwise, it is disabled. + + +##### Key Components + +- `retry`: A map that stores retry operations for documents. Each document in the IntelliJ editor has a corresponding retry operation if an AI Coder action has been performed on it. This map is crucial for tracking which documents have actions that can be redone. + +- `AnActionEvent`: This class from the IntelliJ Platform SDK provides context information about the action event, including data about the current editor and document. It is used to retrieve the document for which the redo operation needs to be performed. + + +##### Conclusion + +The `RedoLast` action enhances the AI Coder experience in IntelliJ by providing a straightforward mechanism to redo the last performed action. By integrating with the IntelliJ action system and utilizing the `retry` map for tracking actions, it offers a seamless way for developers to manage their AI-assisted coding changes. + +# generic\ReplaceWithSuggestionsAction.kt + +The `ReplaceWithSuggestionsAction` class, part of the `com.github.simiacryptus.aicoder.actions.generic` package, extends the functionality of `SelectionAction` to provide a mechanism for suggesting text replacements within an IDE environment. This class is designed to interact with a virtual API to generate text suggestions based on the context of the selected text in the editor. The core functionality revolves around generating suggestions for replacing a selected piece of text with alternatives, potentially improving or altering the code or documentation in meaningful ways. + + +#### Key Components and Logic + + +##### VirtualAPI Interface +- **Purpose**: Defines a contract for suggesting text replacements. It contains a single method, `suggestText`, which takes a template string and a list of examples to generate suggestions. +- **Suggestions Class**: Nested within the `VirtualAPI` interface, this class holds the suggestions returned by the `suggestText` method, encapsulated in a `List`. + + +##### Proxy Initialization +- The `proxy` property lazily initializes an instance of `ChatProxy` tailored to interact with the `VirtualAPI`. It configures the proxy using settings from `AppSettingsState`, such as the default chat model and temperature settings for generating suggestions. + + +##### processSelection Method +- **Purpose**: Overrides the `processSelection` method from `SelectionAction`. It's responsible for processing the text selection and generating replacement suggestions. +- **Logic**: + - Retrieves the selected text and calculates an ideal context length based on the length of the selected text. + - Extracts the text before and after the selection, ensuring the context is of a manageable size for the suggestion engine. + - Calls the `proxy.suggestText` method with a template that includes placeholders for the selected text and the surrounding context. This template is used to generate contextually relevant suggestions. + - Returns the chosen suggestion from a list of options presented to the user. + + +##### choose Method +- **Purpose**: Presents the generated suggestions to the user through a radio button dialog, allowing them to choose the most appropriate replacement. +- **Implementation**: Utilizes `UITools.showRadioButtonDialog` to display the options and capture the user's selection. + + +#### Configuration and Usage +- The `getConfig` method currently returns an empty string, indicating no additional configuration is required for this action. However, this method can be overridden in subclasses to provide specific configurations. +- The class is designed to be used within an IDE environment where actions can be triggered by the user. It requires access to the current project context (`Project`) and the action event (`AnActionEvent`) to function correctly. + + +#### Summary +`ReplaceWithSuggestionsAction` leverages a virtual API to enhance text editing capabilities by suggesting contextually relevant replacements for selected text. It demonstrates a practical application of machine learning models, encapsulated by the `ChatProxy`, to improve developer productivity within an IDE. + +# generic\WebDevelopmentAssistantAction.kt + +The `WebDevelopmentAssistantAction` class is part of a larger system designed to assist in web development tasks by leveraging AI-driven agents. This system is structured to handle user requests, generate web development artifacts (like HTML, CSS, and JavaScript files), and provide architectural guidance for web applications. The core components facilitating these functionalities are the `WebDevApp` and `WebDevAgent` classes, along with their nested classes and enums. + + +#### WebDevApp Class + +The `WebDevApp` class extends `ApplicationServer` and is configured to serve as a web development assistant. It is initialized with a default application name ("Web Dev Assistant v1.1") and a path ("/webdev"). This class handles user messages by creating instances of `WebDevAgent` and starting the agent with the user's message. + + +##### Settings Nested Class + +The `Settings` data class within `WebDevApp` holds configuration settings for the application, including a budget for API usage, a list of tools, and the model to be used for chat interactions (defaulting to `ChatModels.GPT4Turbo`). + + +#### WebDevAgent Class + +`WebDevAgent` is an `ActorSystem` that manages different types of actors to perform specific tasks related to web development. It defines an enum `ActorTypes` to categorize these actors into roles such as HTML, JavaScript, and CSS coding, architecture discussion, code review, and more. + + +##### Actor Prompts and Configuration + +Each actor type is associated with a specific prompt and configuration, guiding the AI to generate appropriate responses for different aspects of web development. For example: + +- **HTMLCodingActor**: Translates user requests into a skeleton HTML file. +- **JavascriptCodingActor**: Generates a JavaScript file based on the user's description. +- **CssCodingActor**: Creates a CSS file for styling the web application. +- **ArchitectureDiscussionActor**: Discusses and outlines a detailed architecture for the web application, suggesting frameworks, libraries, and coding patterns. +- **CodeReviewer**: Reviews code provided by the user, looks for bugs, and suggests fixes in a diff format. + +These actors are initialized with prompts that describe their specific tasks in detail, ensuring that the AI's responses are aligned with the requirements of web development projects. + + +#### Handling User Messages and Generating Code + +When a user sends a message to the `WebDevApp`, a `WebDevAgent` instance is created and tasked with handling the message. The agent uses the defined actors to generate architectural plans, draft code files, and review existing code based on the user's input. The process involves iterative interactions with the AI, where the agent sends prompts to the AI models and processes their responses to produce the desired outputs. + + +#### Summary + +The `WebDevelopmentAssistantAction` system is a sophisticated tool that leverages AI to assist in various aspects of web development, from planning and architecture to coding and code review. By defining specific roles for AI-driven agents and configuring them with detailed prompts, the system can generate accurate and useful responses to facilitate the web development process. + +# markdown\MarkdownImplementActionGroup.kt + +This Kotlin code defines a plugin action group for IntelliJ-based IDEs, specifically targeting the enhancement of Markdown files with automatically generated code snippets in various programming languages. The primary functionality is encapsulated within the `MarkdownImplementActionGroup` class and its nested `MarkdownImplementAction` class. Below is a detailed explanation of the key components and their functionality: + + +#### MarkdownImplementActionGroup Class + +- **Purpose**: Serves as a container for actions that can be performed on Markdown files. It dynamically generates a list of actions based on supported programming languages, allowing users to insert code snippets in these languages into their Markdown documents. + +- **markdownLanguages**: A list of strings representing the programming languages supported for code snippet generation. This includes languages like SQL, Java, C++, Python, and many others. + +- **update(e: AnActionEvent)**: This method is overridden to control the visibility and availability of the action group based on specific conditions. It checks if the current file is a Markdown file and if there is a text selection within it. + +- **isEnabled(e: AnActionEvent)**: A companion object function that determines whether the action group should be enabled. It checks if the current file's language is Markdown and if there is a selected text. + +- **getChildren(e: AnActionEvent?)**: This method generates the child actions (one for each programming language in `markdownLanguages`) that can be executed. These actions are instances of the `MarkdownImplementAction` class, each configured with a specific programming language. + + +#### MarkdownImplementAction Class + +- **Purpose**: Represents an individual action that can be performed; specifically, generating and inserting a code snippet in the specified programming language into a Markdown document. + +- **language**: A private property that stores the programming language for which the code snippet will be generated. + +- **ConversionAPI Interface**: Defines the contract for a service that can convert a given text into a code snippet in a specified programming language. It includes a method `implement` that takes the text to be converted, the human language of the input text, and the target programming language, returning a `ConvertedText` object containing the generated code snippet. + +- **getProxy()**: This method creates a proxy to the conversion API, configured with settings from `AppSettingsState`, such as the model to use and the temperature for the generation process. + +- **processSelection(state: SelectionState, config: String?)**: Overrides a method from the `SelectionAction` class to process the selected text in the Markdown document. It uses the conversion API to generate a code snippet in the specified programming language and formats it as a Markdown code block. + +This code is designed to enhance the functionality of Markdown editing in IntelliJ-based IDEs by allowing users to easily insert code snippets in various programming languages, leveraging an external code generation API. + +# generic\MultiDiffChatAction.kt + +The `MultiDiffChatAction` class is designed to facilitate a chat-based interface that assists users with coding by providing suggestions and modifications to their code. This is achieved through a multi-file diff chat action, where the AI analyzes the provided code and offers improvements or fixes in the form of diffs. Below is a detailed explanation of the key components related to the prompt text, configuration, and the logic closely associated with these elements. + + +#### Key Components + + +##### Prompt Configuration + +The AI's interaction with the user is guided by two main prompts: the `userInterfacePrompt` and the `systemPrompt`. These prompts are configured as follows: + +- **`userInterfacePrompt`**: This prompt is presented to the user and includes a summary of the code files being discussed. It is generated by the `codeSummary()` function, which compiles the code from all files into a markdown format, with each code snippet enclosed in a code block and preceded by the file path. + +- **`systemPrompt`**: This prompt is designed for the AI and includes instructions on how the AI should assist the user. It provides a context that the AI is a helpful entity for coding-related queries and specifies that the responses should include code patches in diff format. The prompt also includes the same code summary as the `userInterfacePrompt`, ensuring that the AI has all the necessary information about the code being discussed. + + +##### Code Summary Generation + +The `codeSummary()` function plays a crucial role in generating the content for both prompts. It iterates over the `codeFiles` map, which contains paths and code content of the files involved, and formats this information into a markdown string. Each file's code is presented with its path as a header and the code itself in a fenced code block, with the appropriate language syntax highlighting based on the file extension. + + +##### Chat Socket Manager Initialization + +The `agents` map is used to store instances of `ChatSocketManager`, which are initialized with the session ID, model, prompts, and other configurations necessary for the chat functionality. The `ChatSocketManager` is responsible for handling the chat interactions, rendering responses, and applying any code modifications suggested by the AI. + + +##### Response Rendering and Code Modification + +The `renderResponse` method of the `ChatSocketManager` is overridden to process the AI's responses. It uses the `renderMarkdown` function to convert the AI's response, which includes diffs and explanations, into HTML. The `addApplyDiffLinks` function is called to process the diffs, apply them to the code, and generate links for updating the code files. This method ensures that any modifications suggested by the AI are reflected in the actual code files and the user interface. + + +#### Conclusion + +The `MultiDiffChatAction` class integrates with the IntelliJ platform to provide a unique coding assistance experience through a chat interface. By leveraging detailed prompts and dynamic response rendering, it facilitates an interactive environment where users can receive and apply coding suggestions from an AI. The careful configuration of prompts and the logic for generating and processing code summaries and diffs are central to the functionality of this feature. + +# SelectionAction.kt + +The `SelectionAction` class is an abstract class designed to facilitate the creation of actions within the IntelliJ platform that operate on a selected portion of text within an editor. It provides a framework for handling text selection, processing the selected text, and optionally modifying it based on a specific configuration. This class is part of a larger system aimed at enhancing coding productivity and automation within the IDE. + + +#### Key Components + + +##### Configuration (`T`) + +- The generic type `T` represents the configuration object for the action. This configuration can hold any necessary settings or parameters required to process the selection. +- The `getConfig(project: Project?): T?` method is designed to retrieve the configuration object. It can be overridden to provide a custom configuration based on the current project context. + + +##### Selection Processing + +- The `processSelection(event: AnActionEvent?, selectionState: SelectionState, config: T?): String` method is an open method intended to be overridden by subclasses. It defines how the selected text should be processed. The method takes an `AnActionEvent`, a `SelectionState` object containing details about the current text selection, and the configuration object of type `T`. It returns a `String` which is the processed text that may replace the original selection. +- The `SelectionState` data class encapsulates various details about the current selection, including the selected text, selection offset, document information, and more. This information aids in processing the selection accurately. + + +##### Selection Handling + +- The `handle(e: AnActionEvent)` method is the entry point for the action. It retrieves the necessary context from the `AnActionEvent`, such as the editor and project, and manages the selection processing workflow. This includes adjusting the selection if necessary, processing the selected text, and applying any changes to the document. +- The `retarget` method adjusts the selection boundaries based on the current selection and the action's requirements. It ensures that there is a valid selection to work with, according to the action's `requiresSelection` property. + + +##### Utility Methods + +- `editorState(editor: Editor): EditorState` retrieves the current state of the editor, including the text, cursor position, and other relevant details. +- `contextRanges(psiFile: PsiFile?, editor: Editor): Array` analyzes the PSI (Program Structure Interface) tree of the current file to determine contextually relevant ranges around the cursor. This can be useful for actions that need to understand the surrounding code structure. + + +##### Enabling the Action + +- The `isEnabled(event: AnActionEvent): Boolean` method determines whether the action should be enabled based on the current context, such as whether there is a valid selection or if the language of the file is supported. + + +#### Usage + +To use the `SelectionAction` class, one must extend it and implement the abstract methods, particularly `processSelection`, to define the action's behavior. The configuration type `T` allows for flexible customization of the action's processing logic, making it adaptable to various use cases within the IntelliJ platform. + +# markdown\MarkdownListAction.kt + +The `MarkdownListAction` class extends `BaseAction` and is designed to enhance the functionality of markdown files within an IDE environment. This action, when triggered, automatically generates and appends a list of new items to an existing markdown list based on the context and content of the selected list. The generation of new list items is facilitated through a proxy to an external AI service, which is configured and invoked within the class. + + +#### Key Components and Logic + + +##### ListAPI Interface +- **Purpose**: Defines the contract for the AI service to generate new list items. +- **Methods**: + - `newListItems(items: List?, count: Int)`: Takes a list of existing items and a desired count for new items to generate a structured response containing the new list items. + + +##### Proxy Configuration +- **Purpose**: Configures and initializes the proxy to the external AI service. +- **Key Elements**: + - Utilizes `ChatProxy` to create a proxy instance conforming to the `ListAPI` interface. + - Configures the proxy with necessary parameters such as the API model, deserializer retries, and an example to guide the AI's response format. + + +##### Action Logic (`handle` Method) +- **Trigger**: Activated when the action is invoked in the IDE. +- **Process Flow**: + 1. Validates the presence of a caret and PSI (Program Structure Interface) file in the event context. + 2. Identifies the smallest intersecting markdown list element based on the caret's selection. + 3. Extracts and trims the text of each item within the identified list. + 4. Determines the indentation and bullet type for the list items. + 5. Invokes the AI service through the proxy to generate new list items based on the existing ones. + 6. Constructs the new list string with appropriate indentation and bullet types. + 7. Inserts the new list items into the document at the specified location. + + +##### Enabling the Action +- **Purpose**: Determines whether the action should be enabled based on the current context. +- **Logic**: + - Checks if the current file is a markdown file and if there is a markdown list element intersecting with the current selection or caret position. + - The action is enabled only if these conditions are met, ensuring relevance and applicability of the action to the user's context. + + +#### Configuration and Invocation +The action's functionality is heavily reliant on the external AI service, which is abstracted through the `ListAPI` interface and accessed via the `ChatProxy`. The proxy is configured with specific parameters, including the AI model to use and an example to guide the generation of new list items. This setup allows for dynamic and context-aware augmentation of markdown lists within the IDE, enhancing productivity and leveraging AI capabilities for content generation. + diff --git a/gradle.properties b/gradle.properties index 9f67ca74..79d50f6e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ pluginName=intellij-aicoder pluginRepositoryUrl=https://github.com/SimiaCryptus/intellij-aicoder -pluginVersion=1.4.1 +pluginVersion=1.4.2 jvmArgs=-Xmx8g org.gradle.jvmargs=-Xmx8g diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/AppServer.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/AppServer.kt new file mode 100644 index 00000000..6f4a536a --- /dev/null +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/AppServer.kt @@ -0,0 +1,114 @@ +package com.github.simiacryptus.aicoder + +import com.github.simiacryptus.aicoder.config.AppSettingsState +import com.github.simiacryptus.aicoder.util.UITools +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.skyenet.webui.chat.ChatServer +import org.eclipse.jetty.server.Server +import org.eclipse.jetty.server.handler.ContextHandlerCollection +import org.eclipse.jetty.webapp.WebAppContext +import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer +import org.slf4j.LoggerFactory +import java.net.InetSocketAddress + +class AppServer( + private val localName: String, + private val port: Int, + project: Project? +) { + + private val log by lazy { LoggerFactory.getLogger(javaClass) } + + val server by lazy { + val server = Server(InetSocketAddress(localName, port)) + server.handler = contexts + server + } + + private val handlers = arrayOf().toMutableList() + + private val contexts by lazy { + val contexts = ContextHandlerCollection() + contexts.handlers = handlers.toTypedArray() + contexts + } + + val appRegistry = mutableMapOf() + + @Synchronized + fun addApp(path: String, socketServer: ChatServer) { + try { + synchronized(serverLock) { + appRegistry[path] = socketServer + if (server.isRunning) server.stop() // Stop the server + handlers += newWebAppContext(socketServer, path) + contexts.handlers = handlers.toTypedArray() + server.handler = contexts + server.start() // Start the server again to reflect the new context + } + } catch (e: Exception) { + log.error("Error while restarting the server with new context", e) + } + } + + private fun newWebAppContext(server: ChatServer, path: String): WebAppContext { + val context = WebAppContext() + JettyWebSocketServletContainerInitializer.configure(context, null) + context.baseResource = server.baseResource + context.classLoader = AppServer::class.java.classLoader + context.contextPath = path + context.welcomeFiles = arrayOf("index.html") + server.configure(context) + return context + } + + + private val serverLock = Object() + private val progressThread = Thread { + try { + UITools.run( + project, "Running CodeChat Server on $port", false + ) { + while (isRunning(it)) { + Thread.sleep(1000) + } + synchronized(serverLock) { + if (it.isCanceled) { + log.info("Server cancelled") + server.stop() + } else { + log.info("Server stopped") + } + } + } + } finally { + log.info("Stopping Server") + server.stop() + } + } + + private fun isRunning(it: ProgressIndicator) = synchronized(serverLock) { !it.isCanceled && server.isRunning } + fun start() { + server.start() + progressThread.start() + } + + companion object { + @Transient + private var server: AppServer? = null + fun getServer(project: Project?): AppServer { + if (null == server || !server!!.server.isRunning) { + server = AppServer( + AppSettingsState.instance.listeningEndpoint, + AppSettingsState.instance.listeningPort, + project + ) + server!!.start() + } + return server!! + } + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/BaseAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/BaseAction.kt index bb96c680..70250bf4 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/BaseAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/BaseAction.kt @@ -9,43 +9,43 @@ import org.slf4j.LoggerFactory import javax.swing.Icon abstract class BaseAction( - name: String? = null, - description: String? = null, - icon: Icon? = null, + name: String? = null, + description: String? = null, + icon: Icon? = null, ) : AnAction(name, description, icon) { - private val log by lazy { LoggerFactory.getLogger(javaClass) } - //override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT + private val log by lazy { LoggerFactory.getLogger(javaClass) } + //override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT - val api: OpenAIClient - get() = IdeaOpenAIClient.instance + val api: OpenAIClient + get() = IdeaOpenAIClient.instance - final override fun update(event: AnActionEvent) { - event.presentation.isEnabledAndVisible = isEnabled(event) - super.update(event) - } + final override fun update(event: AnActionEvent) { + event.presentation.isEnabledAndVisible = isEnabled(event) + super.update(event) + } - abstract fun handle(e: AnActionEvent) + abstract fun handle(e: AnActionEvent) - final override fun actionPerformed(e: AnActionEvent) { - UITools.logAction( - """ + final override fun actionPerformed(e: AnActionEvent) { + UITools.logAction( + """ |Action: ${javaClass.simpleName} """.trimMargin().trim() - ) - IdeaOpenAIClient.lastEvent = e - try { - handle(e) - } catch (e: Throwable) { - UITools.error(log, "Error in Action ${javaClass.simpleName}", e) + ) + IdeaOpenAIClient.lastEvent = e + try { + handle(e) + } catch (e: Throwable) { + UITools.error(log, "Error in Action ${javaClass.simpleName}", e) + } } - } - open fun isEnabled(event: AnActionEvent): Boolean = true + open fun isEnabled(event: AnActionEvent): Boolean = true - companion object { - val log by lazy { LoggerFactory.getLogger(javaClass) } - val scheduledPool = java.util.concurrent.Executors.newScheduledThreadPool(1) - } + companion object { + val log by lazy { LoggerFactory.getLogger(javaClass) } + val scheduledPool = java.util.concurrent.Executors.newScheduledThreadPool(1) + } } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/SelectionAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/SelectionAction.kt index f554704b..d704af4c 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/SelectionAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/SelectionAction.kt @@ -60,7 +60,7 @@ abstract class SelectionAction( UITools.redoableTask(e) { val document = e.getData(CommonDataKeys.EDITOR)?.document - var rangeMarker: RangeMarker? = null + var rangeMarker: RangeMarker? = null WriteCommandAction.runWriteCommandAction(e.project) { rangeMarker = document?.createGuardedBlock(selectionStart, selectionEnd) } @@ -82,7 +82,7 @@ abstract class SelectionAction( config = config ) } finally { - if(null != rangeMarker) + if (null != rangeMarker) WriteCommandAction.runWriteCommandAction(e.project) { document?.removeGuardedBlock(rangeMarker!!) } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CustomEditAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CustomEditAction.kt index 2a97bbd2..45da9645 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CustomEditAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CustomEditAction.kt @@ -4,11 +4,13 @@ import com.github.simiacryptus.aicoder.actions.SelectionAction import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.UITools +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy import javax.swing.JOptionPane open class CustomEditAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT interface VirtualAPI { fun editCode( @@ -24,31 +26,32 @@ open class CustomEditAction : SelectionAction() { ) } - val proxy: VirtualAPI get() { - val chatProxy = ChatProxy( - clazz = VirtualAPI::class.java, - api = api, - temperature = AppSettingsState.instance.temperature, - model = AppSettingsState.instance.smartModel.chatModel(), - ) - chatProxy.addExample( - VirtualAPI.EditedText( - """ + val proxy: VirtualAPI + get() { + val chatProxy = ChatProxy( + clazz = VirtualAPI::class.java, + api = api, + temperature = AppSettingsState.instance.temperature, + model = AppSettingsState.instance.smartModel.chatModel(), + ) + chatProxy.addExample( + VirtualAPI.EditedText( + """ // Print Hello, World! to the console println("Hello, World!") """.trimIndent(), - "java" - ) - ) { - it.editCode( - """println("Hello, World!")""", - "Add code comments", - "java", - "English" - ) + "java" + ) + ) { + it.editCode( + """println("Hello, World!")""", + "Add code comments", + "java", + "English" + ) + } + return chatProxy.create() } - return chatProxy.create() - } override fun getConfig(project: Project?): String { return UITools.showInputDialog( @@ -64,7 +67,7 @@ open class CustomEditAction : SelectionAction() { settings.getRecentCommands("customEdits").addInstructionToHistory(instruction) return proxy.editCode( state.selectedText ?: "", - instruction ?: "", + instruction, state.language?.name ?: "", outputHumanLanguage ).code ?: state.selectedText ?: "" diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DescribeAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DescribeAction.kt index 9eddc07c..661c2eb9 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DescribeAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DescribeAction.kt @@ -4,11 +4,13 @@ import com.github.simiacryptus.aicoder.actions.SelectionAction import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.IndentedText +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy import com.simiacryptus.jopenai.util.StringUtil class DescribeAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT interface DescribeAction_VirtualAPI { fun describeCode( @@ -25,11 +27,11 @@ class DescribeAction : SelectionAction() { private val proxy: DescribeAction_VirtualAPI get() = ChatProxy( - clazz = DescribeAction_VirtualAPI::class.java, - api = api, - temperature = AppSettingsState.instance.temperature, - model = AppSettingsState.instance.smartModel.chatModel(), - deserializerRetries = 5 + clazz = DescribeAction_VirtualAPI::class.java, + api = api, + temperature = AppSettingsState.instance.temperature, + model = AppSettingsState.instance.smartModel.chatModel(), + deserializerRetries = 5 ).create() override fun getConfig(project: Project?): String { diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/PasteAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/PasteAction.kt index 81739c01..5f2a5e8c 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/PasteAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/PasteAction.kt @@ -4,6 +4,7 @@ import com.github.simiacryptus.aicoder.actions.SelectionAction import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.ComputerLanguage +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy @@ -11,56 +12,60 @@ import java.awt.Toolkit import java.awt.datatransfer.DataFlavor open class PasteAction : SelectionAction(false) { + override fun getActionUpdateThread() = ActionUpdateThread.BGT - interface VirtualAPI { - fun convert(text: String, from_language: String, to_language: String): ConvertedText + interface VirtualAPI { + fun convert(text: String, from_language: String, to_language: String): ConvertedText - class ConvertedText { - var code: String? = null - var language: String? = null + class ConvertedText { + var code: String? = null + var language: String? = null + } } - } - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(state: SelectionState, config: String?): String { - return ChatProxy( - VirtualAPI::class.java, - api, - AppSettingsState.instance.smartModel.chatModel(), - AppSettingsState.instance.temperature, - ).create().convert( - getClipboard().toString().trim(), - "autodetect", - state.language?.name ?: "" - ).code ?: "" - } + override fun getConfig(project: Project?): String { + return "" + } - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - if (computerLanguage == null) return false - return computerLanguage != ComputerLanguage.Text - } + override fun processSelection(state: SelectionState, config: String?): String { + return ChatProxy( + VirtualAPI::class.java, + api, + AppSettingsState.instance.smartModel.chatModel(), + AppSettingsState.instance.temperature, + ).create().convert( + getClipboard().toString().trim(), + "autodetect", + state.language?.name ?: "" + ).code ?: "" + } - override fun isEnabled(event: AnActionEvent): Boolean { - if (!hasClipboard()) return false - return super.isEnabled(event) - } + override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { + if (computerLanguage == null) return false + return computerLanguage != ComputerLanguage.Text + } - private fun hasClipboard() = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)?.let { contents -> - return when { - contents.isDataFlavorSupported(DataFlavor.stringFlavor) -> true - contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()) -> true - else -> false + override fun isEnabled(event: AnActionEvent): Boolean { + if (!hasClipboard()) return false + return super.isEnabled(event) } - } ?: false - private fun getClipboard(): Any? = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)?.let { contents -> - return when { - contents.isDataFlavorSupported(DataFlavor.stringFlavor) -> contents.getTransferData(DataFlavor.stringFlavor) - contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()) -> contents.getTransferData(DataFlavor.getTextPlainUnicodeFlavor()) - else -> null + private fun hasClipboard() = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)?.let { contents -> + return when { + contents.isDataFlavorSupported(DataFlavor.stringFlavor) -> true + contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()) -> true + else -> false + } + } ?: false + + private fun getClipboard(): Any? = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)?.let { contents -> + return when { + contents.isDataFlavorSupported(DataFlavor.stringFlavor) -> contents.getTransferData(DataFlavor.stringFlavor) + contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()) -> contents.getTransferData( + DataFlavor.getTextPlainUnicodeFlavor() + ) + + else -> null + } } - } } \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RecentCodeEditsAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RecentCodeEditsAction.kt index b4a17b41..bd5328cc 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RecentCodeEditsAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RecentCodeEditsAction.kt @@ -4,11 +4,14 @@ import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.util.ComputerLanguage import com.github.simiacryptus.aicoder.util.UITools import com.intellij.openapi.actionSystem.ActionGroup +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.Project class RecentCodeEditsAction : ActionGroup() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + override fun update(e: AnActionEvent) { e.presentation.isEnabledAndVisible = isEnabled(e) super.update(e) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/RedoLast.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RedoLast.kt similarity index 82% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/RedoLast.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RedoLast.kt index 5a03da8e..23dac9ef 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/RedoLast.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RedoLast.kt @@ -1,7 +1,8 @@ -package com.github.simiacryptus.aicoder.actions.generic +package com.github.simiacryptus.aicoder.actions.code import com.github.simiacryptus.aicoder.actions.BaseAction import com.github.simiacryptus.aicoder.util.UITools.retry +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys @@ -11,6 +12,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys * This will redo the last action that was performed in the editor. */ class RedoLast : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT override fun handle(e: AnActionEvent) { retry[e.getRequiredData(CommonDataKeys.EDITOR).document]!!.run() diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/AppServer.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/AppServer.kt deleted file mode 100644 index 0e659bc6..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/AppServer.kt +++ /dev/null @@ -1,118 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.dev - -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.simiacryptus.skyenet.webui.chat.ChatServer -import org.eclipse.jetty.server.Server -import org.eclipse.jetty.server.handler.ContextHandlerCollection -import org.eclipse.jetty.webapp.WebAppContext -import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer -import org.slf4j.LoggerFactory -import java.net.InetSocketAddress - -class AppServer( - private val localName: String, - private val port: Int, - project: Project? -) { - - private val log by lazy { LoggerFactory.getLogger(javaClass) } - - val server by lazy { - val server = Server(InetSocketAddress(localName, port)) - server.handler = contexts - server - } - - private val handlers = arrayOf().toMutableList() - - private val contexts by lazy { - val contexts = ContextHandlerCollection() - contexts.handlers = handlers.toTypedArray() - contexts - } - - val appRegistry = mutableMapOf() - - @Synchronized - fun addApp(path: String, socketServer: ChatServer) { - try { - synchronized(serverLock) { - appRegistry[path] = socketServer - if (server.isRunning) server.stop() // Stop the server - handlers += newWebAppContext(socketServer, path) - contexts.handlers = handlers.toTypedArray() - server.handler = contexts - server.start() // Start the server again to reflect the new context - } - } catch (e: Exception) { - log.error("Error while restarting the server with new context", e) - } - } - - private fun newWebAppContext(server: ChatServer, path: String): WebAppContext { - val context = WebAppContext() - JettyWebSocketServletContainerInitializer.configure(context, null) - context.baseResource = server.baseResource - context.classLoader = AppServer::class.java.classLoader - context.contextPath = path - context.welcomeFiles = arrayOf("index.html") - server.configure(context) - return context - } - - - private val serverLock = Object() - private val progressThread = Thread { - try { - UITools.run( - project, "Running CodeChat Server on $port", false - ) { - while (isRunning(it)) { - Thread.sleep(1000) - } - synchronized(serverLock) { - if (it.isCanceled) { - log.info("Server cancelled") - server.stop() - } else { - log.info("Server stopped") - } - } - } - } finally { - log.info("Stopping Server") - server.stop() - } - } - - private fun isRunning(it: ProgressIndicator) = synchronized(serverLock) { !it.isCanceled && server.isRunning } - fun start() { - server.start() - progressThread.start() - } - - companion object { - @Transient - private var server: AppServer? = null - fun getServer(project: Project?): AppServer { - if (null == server || !server!!.server.isRunning) { - server = AppServer( - AppSettingsState.instance.listeningEndpoint, - AppSettingsState.instance.listeningPort, - project - ) - server!!.start() - } - return server!! - } - - fun stop() { - server?.server?.stop() - server = null - } - } - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/LineFilterChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/LineFilterChatAction.kt similarity index 93% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/LineFilterChatAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/LineFilterChatAction.kt index f311d568..7f3330a2 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/LineFilterChatAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/LineFilterChatAction.kt @@ -1,14 +1,14 @@ -package com.github.simiacryptus.aicoder.actions.generic +package com.github.simiacryptus.aicoder.actions.dev import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.dev.AppServer +import com.github.simiacryptus.aicoder.AppServer import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.ComputerLanguage +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.fileEditor.FileDocumentManager -import com.simiacryptus.skyenet.core.actors.CodingActor.Companion.indent import com.simiacryptus.skyenet.core.platform.ApplicationServices import com.simiacryptus.skyenet.core.platform.Session import com.simiacryptus.skyenet.core.platform.StorageInterface @@ -24,6 +24,7 @@ import java.awt.Desktop import java.io.File class LineFilterChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT val path = "/codeChat" @@ -44,7 +45,7 @@ class LineFilterChatAction : BaseAction() { |# `$filename` | |```$language - |${code?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} + |${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} |``` """.trimMargin().trim(), systemPrompt = """ @@ -53,7 +54,7 @@ class LineFilterChatAction : BaseAction() { |You will be answering questions about the following code located in `$filename`: | |```$language - |${codelines?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} + |${codelines.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} |``` | |Responses may use markdown formatting. Lines from the prompt can be included by using the line number in a response line (e.g. `\nLINE\n`). diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/PrintTreeAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/PrintTreeAction.kt index 78e0b8a2..70497435 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/PrintTreeAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/PrintTreeAction.kt @@ -3,6 +3,7 @@ import com.github.simiacryptus.aicoder.actions.BaseAction import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.util.psi.PsiUtil +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import org.slf4j.LoggerFactory @@ -14,7 +15,7 @@ import org.slf4j.LoggerFactory * This will print the tree structure of the file to the log. */ class PrintTreeAction : BaseAction() { - + override fun getActionUpdateThread() = ActionUpdateThread.BGT override fun handle(e: AnActionEvent) { log.warn(PsiUtil.printTree(PsiUtil.getLargestContainedEntity(e)!!)) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AnalogueFileAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AnalogueFileAction.kt deleted file mode 100644 index bb6c90f2..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AnalogueFileAction.kt +++ /dev/null @@ -1,169 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.actions.FileContextAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel -import com.github.simiacryptus.aicoder.config.Name -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.LocalFileSystem -import com.simiacryptus.jopenai.ApiModel -import com.simiacryptus.jopenai.ApiModel.ChatMessage -import com.simiacryptus.jopenai.ApiModel.Role -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import com.simiacryptus.skyenet.core.actors.CodingActor.Companion.indent -import org.apache.commons.io.FileUtils -import org.apache.commons.io.IOUtils -import org.apache.commons.text.StringEscapeUtils.escapeHtml4 -import java.io.File -import java.io.FileInputStream -import java.nio.file.Path -import java.util.concurrent.TimeUnit -import javax.swing.JTextArea - -class AnalogueFileAction : FileContextAction() { - override fun isEnabled(event: AnActionEvent): Boolean { - if (UITools.getSelectedFile(event)?.isDirectory == true) return false - return super.isEnabled(event) - } - - data class ProjectFile( - val path: String = "", - val code: String = "" - ) - - class SettingsUI { - @Name("Directive") - var directive: JTextArea = JTextArea( - """ - Create test cases - """.trimIndent(), - 3, - 120 - ) - } - - class UserSettings( - var directive: String = "", - ) - - class Settings( - val settings: UserSettings? = null, - val project: Project? = null - ) - - override fun getConfig(project: Project?, e: AnActionEvent): Settings { - return Settings( - UITools.showDialog( - project, - SettingsUI::class.java, - UserSettings::class.java, - "Create Analogue File" - ), project - ) - } - - override fun processSelection(state: SelectionState, config: Settings?): Array { - val root = getModuleRootForFile(state.selectedFile).toPath() - val selectedFile = state.selectedFile - val analogue = generateFile( - ProjectFile( - path = root.relativize(selectedFile.toPath()).toString(), - code = IOUtils.toString(FileInputStream(selectedFile), "UTF-8") - ), - config?.settings?.directive ?: "" - ) - var outputPath = root.resolve(analogue.path) - if (outputPath.toFile().exists()) { - val extension = outputPath.toString().split(".").last() - val name = outputPath.toString().split(".").dropLast(1).joinToString(".") - val fileIndex = (1..Int.MAX_VALUE).find { - !root.resolve("$name.$it.$extension").toFile().exists() - } - outputPath = root.resolve("$name.$fileIndex.$extension") - } - outputPath.parent.toFile().mkdirs() - FileUtils.write(outputPath.toFile(), analogue.code, "UTF-8") - open(config?.project!!, outputPath) - return arrayOf(outputPath.toFile()) - } - - private fun generateFile(baseFile: ProjectFile, directive: String): ProjectFile { - val model = AppSettingsState.instance.smartModel.chatModel() - val chatRequest = ApiModel.ChatRequest( - model = model.modelName, - temperature = AppSettingsState.instance.temperature, - messages = listOf( - ChatMessage( - Role.system, """ - You will combine natural language instructions with a user provided code example to create a new file. - Provide a new filename and the code to be written to the file. - Paths should be relative to the project root and should not exist. - Output the file path using the a line with the format "File: ". - Output the file code directly after the header line with no additional decoration. - """.trimIndent().toContentList(), null - ), - ChatMessage( - Role.user, """ - |Create a new file based on the following directive: $directive - | - |The file should be based on `${baseFile.path}` which contains the following code: - | - |``` - |${baseFile.code?.let { /*escapeHtml4*/it/*.indent(" ")*/ }} - |``` - """.trimMargin().toContentList(), null - ) - - ) - ) - val response = api.chat(chatRequest, model).choices.first().message?.content?.trim() - var outputPath = baseFile.path - val header = response?.split("\n")?.first() - var body = response?.split("\n")?.drop(1)?.joinToString("\n")?.trim() - if (body?.contains("```") == true) { - body = body.split("```.*".toRegex()).drop(1).firstOrNull()?.trim() ?: body - } - val pathPattern = "File(?:name)?: ['\"]?([^'\"]+)['\"]?".toRegex() - val matcher = pathPattern.find(header ?: "") - if (matcher != null) { - outputPath = matcher.groupValues[1].trim() - } - return ProjectFile( - path = outputPath, - code = body ?: "" - ) - } - - companion object { - fun open(project: Project, outputPath: Path) { - lateinit var function: () -> Unit - function = { - val file = outputPath.toFile() - if (file.exists()) { - // Ensure the IDE is ready for file operations - ApplicationManager.getApplication().invokeLater { - val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) - if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { - val localFileSystem = LocalFileSystem.getInstance() - // Refresh the file system to ensure the file is visible - val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) - virtualFile?.let { - FileEditorManager.getInstance(project).openFile(it, true) - } ?: scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } else { - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - } else { - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AppendAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AppendAction.kt deleted file mode 100644 index 0df10210..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AppendAction.kt +++ /dev/null @@ -1,32 +0,0 @@ - package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.ApiModel.* -import com.simiacryptus.jopenai.util.ClientUtil.toContentList - - class AppendAction : SelectionAction() { - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(state: SelectionState, config: String?): String { - val settings = AppSettingsState.instance - val request = ChatRequest( - model = settings.smartModel.chatModel().modelName, - temperature = settings.temperature - ).copy( - temperature = settings.temperature, - messages = listOf( - ChatMessage(Role.system, "Append text to the end of the user's prompt".toContentList(), null), - ChatMessage(Role.user, state.selectedText.toString().toContentList(), null) - ), - ) - val chatResponse = api.chat(request, settings.smartModel.chatModel()) - val b4 = state.selectedText ?: "" - val str = chatResponse.choices[0].message?.content ?: "" - return b4 + if (str.startsWith(b4)) str.substring(b4.length) else str - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AutoDevAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AutoDevAction.kt deleted file mode 100644 index 937497d1..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/AutoDevAction.kt +++ /dev/null @@ -1,320 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.dev.AppServer -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.UITools -import com.github.simiacryptus.diff.addApplyFileDiffLinks -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.ApiModel -import com.simiacryptus.jopenai.ApiModel.Role -import com.simiacryptus.jopenai.describe.Description -import com.simiacryptus.jopenai.models.ChatModels -import com.simiacryptus.jopenai.proxy.ValidatedObject -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import com.simiacryptus.jopenai.util.JsonUtil.toJson -import com.simiacryptus.skyenet.Acceptable -import com.simiacryptus.skyenet.AgentPatterns -import com.simiacryptus.skyenet.Retryable -import com.simiacryptus.skyenet.core.actors.* -import com.simiacryptus.skyenet.core.platform.* -import com.simiacryptus.skyenet.core.platform.file.DataStorage -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.chat.ChatServer -import com.simiacryptus.skyenet.webui.util.MarkdownUtil.renderMarkdown -import org.slf4j.LoggerFactory -import java.awt.Desktop -import java.io.File -import java.util.concurrent.Semaphore -import java.util.concurrent.atomic.AtomicReference - -class AutoDevAction : BaseAction() { - - val path = "/autodev" - - override fun handle(e: AnActionEvent) { - val session = StorageInterface.newGlobalID() - val storage = ApplicationServices.dataStorageFactory(DiffChatAction.root) as DataStorage? - val selectedFile = UITools.getSelectedFolder(e) - if (null != storage && null != selectedFile) { - DataStorage.sessionPaths[session] = selectedFile.toFile - } - agents[session] = AutoDevApp(event = e) - val server = AppServer.getServer(e.project) - val app = initApp(server, path) - app.sessions[session] = app.newSession(null, session) - Thread { - Thread.sleep(500) - try { - Desktop.getDesktop().browse(server.server.uri.resolve("$path/#$session")) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - open class AutoDevApp( - applicationName: String = "Auto Dev Assistant v1.1", - open val symbols: Map = mapOf(), - val temperature: Double = 0.1, - val event: AnActionEvent, - ) : ApplicationServer( - applicationName = applicationName, - path = "/autodev", - showMenubar = false, - ) { - override fun userMessage( - session: Session, - user: User?, - userMessage: String, - ui: ApplicationInterface, - api: API - ) { - val settings = getSettings(session, user) ?: Settings() - if (api is ClientManager.MonitoredClient) api.budget = settings.budget ?: 2.00 - AutoDevAgent( - api = api, - dataStorage = dataStorage, - session = session, - user = user, - ui = ui, - tools = settings.tools, - model = settings.model!!, - event = event, - parsingModel = AppSettingsState.instance.defaultFastModel(), - ).start( - userMessage = userMessage, - ) - } - - data class Settings( - val budget: Double? = 2.00, - val tools: List = emptyList(), - val model: ChatModels? = AppSettingsState.instance.defaultSmartModel(), - ) - - override val settingsClass: Class<*> get() = Settings::class.java - - @Suppress("UNCHECKED_CAST") - override fun initSettings(session: Session): T? = Settings() as T - } - - class AutoDevAgent( - val api: API, - dataStorage: StorageInterface, - session: Session, - user: User?, - val ui: ApplicationInterface, - val model: ChatModels, - val parsingModel: ChatModels, - val tools: List = emptyList(), - actorMap: Map> = mapOf( - ActorTypes.DesignActor to ParsedActor( - resultClass = TaskList::class.java, - prompt = """ - Translate the user directive into an action plan for the project. - Break the user's request into a list of simple tasks to be performed. - For each task, provide a list of files to be modified and a description of the changes to be made. - """.trimIndent(), - model = model, - parsingModel = parsingModel, - ), - ActorTypes.TaskCodingActor to SimpleActor( - prompt = """ - Implement the changes to the codebase as described in the task list. - - Response should use one or more code patches in diff format within ```diff code blocks. - Each diff should be preceded by a header that identifies the file being modified. - The diff format should use + for line additions, - for line deletions. - The diff should include 2 lines of context before and after every change. - - Example: - - Explanation text - - ### scripts/filename.js - ```diff - import com.simiacryptus.skyenet.webui.components.CheckboxTab - - const b = 2; - + const a = 1; - ``` - - Continued text - """.trimIndent(), - model = model - ), - ), - val event: AnActionEvent, - ) : ActorSystem( - actorMap.map { it.key.name to it.value }.toMap(), dataStorage, user, session - ) { - enum class ActorTypes { - DesignActor, - TaskCodingActor, - } - - private val designActor by lazy { getActor(ActorTypes.DesignActor) as ParsedActor } - private val taskActor by lazy { getActor(ActorTypes.TaskCodingActor) as SimpleActor } - - fun start( - userMessage: String, - ) { - val codeFiles = mutableMapOf() - val root = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext) - ?.map { it.toFile.toPath() }?.toTypedArray()?.commonRoot()!! - PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext)?.forEach { file -> - val code = file.inputStream.bufferedReader().use { it.readText() } - codeFiles[root.relativize(file.toNioPath()).toString()] = code - } - require(codeFiles.isNotEmpty()) { "No files selected" } - fun codeSummary() = codeFiles.entries.joinToString("\n\n") { (path, code) -> - "# $path\n```${ - path.split('.').last() - }\n${code/*.indent(" ")*/}\n```" - } - - val task = ui.newTask() - val toInput = { it: String -> listOf(codeSummary(), it) } - val architectureResponse = Acceptable( - task = task, - userMessage = userMessage, - initialResponse = { it: String -> designActor.answer(toInput(it), api = api) }, - outputFn = { design: ParsedResponse -> - // renderMarkdown("${design.text}\n\n```json\n${JsonUtil.toJson(design.obj)/*.indent(" ")*/}\n```") - AgentPatterns.displayMapInTabs( - mapOf( - "Text" to renderMarkdown(design.text, ui=ui), - "JSON" to renderMarkdown("```json\n${toJson(design.obj)/*.indent(" ")*/}\n```", ui=ui), - ) - ) - }, - ui = ui, - reviseResponse = { userMessages: List> -> - designActor.respond( - messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } - .toTypedArray()), - input = toInput(userMessage), - api = api - ) - }, - atomicRef = AtomicReference(), - semaphore = Semaphore(0), - heading = userMessage - ).call() - - try { - architectureResponse.obj.tasks.forEach { (paths, description) -> - task.complete(ui.hrefLink(renderMarkdown("Task: $description", ui=ui)) { - val task = ui.newTask() - task.header("Task: $description") - val process = { it: StringBuilder -> - val filter = codeFiles.filter { (path, _) -> paths?.find { path.contains(it) }?.isNotEmpty() == true } - require(filter.isNotEmpty()) { - """ - |No files found for $paths - | - |Root: - |$root - | - |Files: - |${codeFiles.keys.joinToString("\n")} - | - |Paths: - |${paths?.joinToString("\n") ?: ""} - | - """.trimMargin() - } - ui.socketManager.addApplyFileDiffLinks( - root = root, - code = codeFiles, - response = taskActor.answer(listOf( - codeSummary(), - userMessage, - filter.entries.joinToString("\n\n") { - "# ${it.key}\n```${ - it.key.split('.').last()?.let { /*escapeHtml4*/it/*.indent(" ")*/ } - }\n${it.value/*.indent(" ")*/}\n```" - }, - architectureResponse.text, - "Provide a change for ${paths?.joinToString(",") { it } ?: ""} ($description)" - ), api), - handle = { newCodeMap -> - newCodeMap.forEach { (path, newCode) -> - val prev = codeFiles[path] - if (prev != newCode) { - codeFiles[path] = newCode - task.complete( - "$path Updated" - ) - } - } - }, - ui = ui - ) - } - Retryable(ui, task, process).apply { set(label(size), process(container!!)) } - }) - } - } catch (e: Throwable) { - log.warn("Error", e) - task.error(ui, e) - } - } - } - - val taskStates = mutableMapOf() - - companion object { - private val log = LoggerFactory.getLogger(AutoDevAction::class.java) - private val agents = mutableMapOf() - val root: File get() = File(AppSettingsState.instance.pluginHome, "code_chat") - private fun initApp(server: AppServer, path: String): ChatServer { - server.appRegistry[path]?.let { return it } - val socketServer = object : ApplicationServer(applicationName = "Code Chat", path = path) { - override val singleInput = true - override val stickyInput = false - override fun newSession(user: User?, session: Session) = agents[session]!!.newSession(user, session) - } - server.addApp(path, socketServer) - return socketServer - } - - data class TaskList( - @Description("List of tasks to be performed in this project") - val tasks: List = emptyList() - ) : ValidatedObject { - override fun validate(): String? = when { - tasks.isEmpty() -> "Resources are required" - tasks.any { it.validate() != null } -> "Invalid resource" - else -> null - } - } - - data class Task( - @Description("List of paths involved in the task. This should include all files to be modified, and can include other files whose content will be informative in writing the changes.") - val paths: List? = null, - @Description("Detailed description of the changes to be made. Markdown format is supported.") - val description: String? = null - ) : ValidatedObject { - override fun validate(): String? = when { - paths.isNullOrEmpty() -> "Paths are required" - paths.any { it.isBlank() } -> "Invalid path" - else -> null - } - } - - } - enum class TaskState { - Pending, - InProgress, - Completed - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CodeChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CodeChatAction.kt index 3d76bc9b..d5757a9f 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CodeChatAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CodeChatAction.kt @@ -1,11 +1,12 @@ package com.github.simiacryptus.aicoder.actions.generic import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.dev.AppServer +import com.github.simiacryptus.aicoder.AppServer import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.CodeChatSocketManager import com.github.simiacryptus.aicoder.util.ComputerLanguage +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.fileEditor.FileDocumentManager @@ -21,6 +22,7 @@ import java.awt.Desktop import java.io.File class CodeChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT val path = "/codeChat" diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileAction.kt deleted file mode 100644 index 1e95ad49..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileAction.kt +++ /dev/null @@ -1,95 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.actions.FileContextAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel -import com.simiacryptus.jopenai.ApiModel.* -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import java.io.File - -class CreateFileAction : FileContextAction(false, true) { - - class ProjectFile(var path: String = "", var code: String = "") - - class Settings(var directive: String = "") - - override fun processSelection( - state: SelectionState, - config: Settings? - ): Array { - val projectRoot = state.projectRoot.toPath() - val inputPath = projectRoot.relativize(state.selectedFile.toPath()).toString() - val pathSegments = inputPath.split("/").toList() - val updirSegments = pathSegments.takeWhile { it == ".." } - val moduleRoot = projectRoot.resolve(pathSegments.take(updirSegments.size * 2).joinToString("/")) - val filePath = pathSegments.drop(updirSegments.size * 2).joinToString("/") - - val generatedFile = generateFile(filePath, config?.directive ?: "") - - var path = generatedFile.path - var outputPath = moduleRoot.resolve(path) - if (outputPath.toFile().exists()) { - val extension = path.substringAfterLast(".") - val name = path.substringBeforeLast(".") - val fileIndex = (1..Int.MAX_VALUE).find { - !File("$name.$it.$extension").exists() - } - path = "$name.$fileIndex.$extension" - outputPath = projectRoot.resolve(path) - } - outputPath.parent.toFile().mkdirs() - outputPath.toFile().writeText(generatedFile.code) - Thread.sleep(100) - - return arrayOf(outputPath.toFile()) - } - - private fun generateFile( - basePath: String, - directive: String - ): ProjectFile { - val model = AppSettingsState.instance.smartModel.chatModel() - val chatRequest = ChatRequest( - model = model.modelName, - temperature = AppSettingsState.instance.temperature, - messages = listOf( - ChatMessage( - Role.system, """ - You will interpret natural language requirements to create a new file. - Provide a new filename and the code to be written to the file. - Paths should be relative to the project root and should not exist. - Output the file path using the a line with the format "File: ". - Output the file code directly after the header line with no additional decoration. - """.trimIndent().toContentList(), null - ), - ChatMessage( - Role.user, """ - Create a new file based on the following directive: $directive - - The file location should be based on the selected path `$basePath` - """.trimIndent().toContentList(), null - ) - ) - ) - val response = api.chat( - chatRequest, - AppSettingsState.instance.smartModel.chatModel() - ).choices?.first()?.message?.content?.trim() ?: "" - var outputPath = basePath - val header = response.lines().first() - var body = response.lines().drop(1).joinToString("\n").trim() - if (body.startsWith("```")) { - // Remove beginning ``` (optionally ```language) and ending ``` - body = body.split("\n").drop(1).joinToString("\n").trim() - } - val pathPattern = """File(?:name)?: ['`"]?([^'`"]+)['`"]?""".toRegex() - if (pathPattern.matches(header)) { - val match = pathPattern.matchEntire(header)!! - outputPath = match.groupValues[1] - } - return ProjectFile( - path = outputPath, - code = body - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileFromDescriptionAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileFromDescriptionAction.kt new file mode 100644 index 00000000..144bfa66 --- /dev/null +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileFromDescriptionAction.kt @@ -0,0 +1,97 @@ +package com.github.simiacryptus.aicoder.actions.generic + +import com.github.simiacryptus.aicoder.actions.FileContextAction +import com.github.simiacryptus.aicoder.config.AppSettingsState +import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.simiacryptus.jopenai.ApiModel.* +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import java.io.File + +class CreateFileFromDescriptionAction : FileContextAction(false, true) { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + class ProjectFile(var path: String = "", var code: String = "") + + class Settings(var directive: String = "") + + override fun processSelection( + state: SelectionState, + config: Settings? + ): Array { + val projectRoot = state.projectRoot.toPath() + val inputPath = projectRoot.relativize(state.selectedFile.toPath()).toString() + val pathSegments = inputPath.split("/").toList() + val updirSegments = pathSegments.takeWhile { it == ".." } + val moduleRoot = projectRoot.resolve(pathSegments.take(updirSegments.size * 2).joinToString("/")) + val filePath = pathSegments.drop(updirSegments.size * 2).joinToString("/") + + val generatedFile = generateFile(filePath, config?.directive ?: "") + + var path = generatedFile.path + var outputPath = moduleRoot.resolve(path) + if (outputPath.toFile().exists()) { + val extension = path.substringAfterLast(".") + val name = path.substringBeforeLast(".") + val fileIndex = (1..Int.MAX_VALUE).find { + !File("$name.$it.$extension").exists() + } + path = "$name.$fileIndex.$extension" + outputPath = projectRoot.resolve(path) + } + outputPath.parent.toFile().mkdirs() + outputPath.toFile().writeText(generatedFile.code) + Thread.sleep(100) + + return arrayOf(outputPath.toFile()) + } + + private fun generateFile( + basePath: String, + directive: String + ): ProjectFile { + val model = AppSettingsState.instance.smartModel.chatModel() + val chatRequest = ChatRequest( + model = model.modelName, + temperature = AppSettingsState.instance.temperature, + messages = listOf( + ChatMessage( + Role.system, """ + You will interpret natural language requirements to create a new file. + Provide a new filename and the code to be written to the file. + Paths should be relative to the project root and should not exist. + Output the file path using the a line with the format "File: ". + Output the file code directly after the header line with no additional decoration. + """.trimIndent().toContentList(), null + ), + ChatMessage( + Role.user, """ + Create a new file based on the following directive: $directive + + The file location should be based on the selected path `$basePath` + """.trimIndent().toContentList(), null + ) + ) + ) + val response = api.chat( + chatRequest, + AppSettingsState.instance.smartModel.chatModel() + ).choices.first()?.message?.content?.trim() ?: "" + var outputPath = basePath + val header = response.lines().first() + var body = response.lines().drop(1).joinToString("\n").trim() + if (body.startsWith("```")) { + // Remove beginning ``` (optionally ```language) and ending ``` + body = body.split("\n").drop(1).joinToString("\n").trim() + } + val pathPattern = """File(?:name)?: ['`"]?([^'`"]+)['`"]?""".toRegex() + if (pathPattern.matches(header)) { + val match = pathPattern.matchEntire(header)!! + outputPath = match.groupValues[1] + } + return ProjectFile( + path = outputPath, + code = body + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DiffChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DiffChatAction.kt index cfca05c2..dd9cf29e 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DiffChatAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DiffChatAction.kt @@ -1,21 +1,22 @@ package com.github.simiacryptus.aicoder.actions.generic import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.dev.AppServer +import com.github.simiacryptus.aicoder.AppServer import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.CodeChatSocketManager import com.github.simiacryptus.aicoder.util.ComputerLanguage import com.github.simiacryptus.diff.addApplyDiffLinks +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.util.TextRange import com.simiacryptus.skyenet.core.platform.ApplicationServices import com.simiacryptus.skyenet.core.platform.Session import com.simiacryptus.skyenet.core.platform.StorageInterface import com.simiacryptus.skyenet.core.platform.User -import com.simiacryptus.skyenet.set import com.simiacryptus.skyenet.webui.application.ApplicationInterface import com.simiacryptus.skyenet.webui.application.ApplicationServer import com.simiacryptus.skyenet.webui.chat.ChatServer @@ -27,19 +28,20 @@ import java.awt.Desktop import java.io.File class DiffChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT val path = "/diffChat" override fun handle(e: AnActionEvent) { val editor = e.getData(CommonDataKeys.EDITOR) ?: return val session = StorageInterface.newGlobalID() - val language = ComputerLanguage.getComputerLanguage(e)?.name ?: return + val language = ComputerLanguage.getComputerLanguage(e)?.name ?: "" val document = editor.document val filename = FileDocumentManager.getInstance().getFile(document)?.name ?: return val primaryCaret = editor.caretModel.primaryCaret val rawText: String val selectionStart: Int - val selectionEnd: Int + var selectionEnd: Int val selectedText = primaryCaret.selectedText if (null != selectedText) { rawText = selectedText @@ -50,15 +52,10 @@ class DiffChatAction : BaseAction() { selectionStart = 0 selectionEnd = rawText.length } - val numberedText = rawText.split("\n") - .mapIndexed { lineNumber: Int, lineText: String -> - lineText -// String.format("%4d: %s", lineNumber + 1, lineText) - }.joinToString("\n") agents[session] = object : CodeChatSocketManager( session = session, language = language, - codeSelection = numberedText, + codeSelection = rawText, filename = filename, api = api, model = AppSettingsState.instance.smartModel.chatModel(), @@ -87,16 +84,23 @@ class DiffChatAction : BaseAction() { """.trimIndent() val ui by lazy { ApplicationInterface(this) } - override fun renderResponse(response: String, task: SessionTask): String { - val codeBuffer = StringBuilder(rawText) - val withLinks = addApplyDiffLinks(codeBuffer, response, handle = { newCode: String -> - WriteCommandAction.runWriteCommandAction(e.project) { - document.replaceString(selectionStart, selectionStart + codeBuffer.length, newCode) - } - codeBuffer.set(newCode) - }, task = task, ui = ui) - return """
${renderMarkdown(withLinks)}
""" - } + override fun renderResponse(response: String, task: SessionTask) = """
${ + renderMarkdown( + addApplyDiffLinks( + code = { + editor.document.getText(TextRange(selectionStart, selectionEnd)) + }, + response = response, + handle = { newCode: String -> + WriteCommandAction.runWriteCommandAction(e.project) { + selectionEnd = selectionStart + newCode.length + document.replaceString(selectionStart, selectionStart + rawText.length, newCode) + } + }, + task = task, + ui = ui + ) + )}
""" } val server = AppServer.getServer(e.project) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DocumentationCompilerAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DocumentationCompilerAction.kt deleted file mode 100644 index 270eeacb..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DocumentationCompilerAction.kt +++ /dev/null @@ -1,233 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.actions.FileContextAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel -import com.github.simiacryptus.aicoder.config.Name -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.openapi.vfs.LocalFileSystem -import com.intellij.ui.CheckBoxList -import com.intellij.ui.components.JBScrollPane -import com.intellij.ui.components.JBTextArea -import com.intellij.ui.components.JBTextField -import com.simiacryptus.jopenai.ApiModel -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import org.apache.commons.io.IOUtils -import java.awt.BorderLayout -import java.awt.Dimension -import java.io.File -import java.io.FileInputStream -import java.nio.file.Files -import java.nio.file.Path -import java.util.concurrent.Executors -import java.util.concurrent.Future -import java.util.concurrent.TimeUnit -import javax.swing.BoxLayout -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel - - -class DocumentationCompilerAction : FileContextAction() { - - override fun isEnabled(event: AnActionEvent): Boolean { - if (UITools.getSelectedFile(event)?.isDirectory == false) return false - return super.isEnabled(event) - } - - class SettingsUI { - @Name("Files to Process") - val filesToProcess = CheckBoxList() - - @Name("AI Instruction") - val transformationMessage = JBTextArea(4, 40) - - @Name("Output File") - val outputFilename = JBTextField() - } - - class UserSettings( - var transformationMessage: String = "Create user documentation", - var outputFilename: String = "compiled_documentation.md", - var filesToProcess: List = listOf(), - ) - - class Settings( - val settings: UserSettings? = null, - val project: Project? = null - ) - - override fun getConfig(project: Project?, e: AnActionEvent): Settings { - val root = UITools.getSelectedFolder(e)?.toNioPath() - val files = Files.walk(root) - .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } - .toList().filterNotNull().toTypedArray() - val settingsUI = SettingsUI().apply { - filesToProcess.setItems(files.toMutableList()) { path -> - root?.relativize(path)?.toString() ?: path.toString() - } - files.forEach { path -> - filesToProcess.setItemSelected(path, true) - } - } - val dialog = DocumentationCompilerDialog(project, settingsUI) - dialog.show() - val result = dialog.isOK - val settings: UserSettings = dialog.userSettings - settings.filesToProcess = when { - result -> files.filter { path -> settingsUI.filesToProcess.isItemSelected(path) }.toList() - else -> listOf() - } - //.map { path -> return@map root?.resolve(path) }.filterNotNull() - return Settings(settings, project) - } - - override fun processSelection(state: SelectionState, config: Settings?): Array { - val root = state.selectedFile.toPath() - var outputPath = root.resolve(config?.settings?.outputFilename ?: "compiled_documentation.md") - if (outputPath.toFile().exists()) { - val extension = outputPath.toString().split(".").last() - val name = outputPath.toString().split(".").dropLast(1).joinToString(".") - val fileIndex = (1..Int.MAX_VALUE).find { - !root.resolve("$name.$it.$extension").toFile().exists() - } - outputPath = root.resolve("$name.$fileIndex.$extension") - } - val executorService = Executors.newFixedThreadPool(4) - outputPath.parent.toFile().mkdirs() - val transformationMessage = config?.settings?.transformationMessage ?: "Create user documentation" - val markdownContent = StringBuilder() - try { - val selectedPaths = config?.settings?.filesToProcess ?: listOf() - val partitionedPaths = Files.walk(root) - .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } - .toList().groupBy { selectedPaths.contains(it) } - val pathList = partitionedPaths[true]!! - .toList().filterNotNull() - .map> { path -> - executorService.submit { - val fileContent = IOUtils.toString(FileInputStream(path.toFile()), "UTF-8") ?: return@submit null - val transformContent = transformContent(fileContent, transformationMessage) - markdownContent.append("# ${root.relativize(path)}\n\n") - markdownContent.append(transformContent.replace("(?s)(? - try { - future.get() ?: return@map null - } catch (e: Exception) { - log.warn("Error processing file", e) - return@map null - } - }.filterNotNull() - Files.write(outputPath, markdownContent.toString().toByteArray()) - open(config?.project!!, outputPath) - return arrayOf(outputPath.toFile()) - } finally { - executorService.shutdown() - } - } - - private fun transformContent(fileContent: String, transformationMessage: String) = api.chat( - ApiModel.ChatRequest( - model = AppSettingsState.instance.smartModel.chatModel().modelName, - temperature = AppSettingsState.instance.temperature, - messages = listOf( - ApiModel.ChatMessage( - ApiModel.Role.system, """ - You will combine natural language instructions with a user provided code example to document code. - """.trimIndent().toContentList(), null - ), - ApiModel.ChatMessage(ApiModel.Role.user, fileContent.toContentList()), - ApiModel.ChatMessage(ApiModel.Role.user, transformationMessage.toContentList()), - ), - ), - AppSettingsState.instance.smartModel.chatModel() - ).choices.first().message?.content?.trim() ?: fileContent - - companion object { - private val scheduledPool = Executors.newScheduledThreadPool(1) - fun open(project: Project, outputPath: Path) { - lateinit var function: () -> Unit - function = { - val file = outputPath.toFile() - if (file.exists()) { - // Ensure the IDE is ready for file operations - ApplicationManager.getApplication().invokeLater { - val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) - if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { - val localFileSystem = LocalFileSystem.getInstance() - // Refresh the file system to ensure the file is visible - val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) - virtualFile?.let { - FileEditorManager.getInstance(project).openFile(it, true) - } ?: scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } else { - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - } else { - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - - class DocumentationCompilerDialog(project: Project?, private val settingsUI: SettingsUI) : DialogWrapper(project) { - val userSettings = UserSettings() - - init { - title = "Compile Documentation" - // Set the default values for the UI elements from userSettings - settingsUI.transformationMessage.text = userSettings.transformationMessage - settingsUI.outputFilename.text = userSettings.outputFilename - init() - } - - override fun createCenterPanel(): JComponent? { - val panel = JPanel(BorderLayout()).apply { - val filesScrollPane = JBScrollPane(settingsUI.filesToProcess).apply { - preferredSize = Dimension(400, 300) // Adjust the preferred size as needed - } - add(JLabel("Files to Process"), BorderLayout.NORTH) - add(filesScrollPane, BorderLayout.CENTER) // Make the files list the dominant element - - val optionsPanel = JPanel().apply { - layout = BoxLayout(this, BoxLayout.Y_AXIS) - add(JLabel("AI Instruction")) - add(settingsUI.transformationMessage) - add(JLabel("Output File")) - add(settingsUI.outputFilename) - } - add(optionsPanel, BorderLayout.SOUTH) - } - return panel - } - - override fun doOKAction() { - super.doOKAction() - userSettings.transformationMessage = settingsUI.transformationMessage.text - userSettings.outputFilename = settingsUI.outputFilename.text - // Assuming filesToProcess already reflects the user's selection -// userSettings.filesToProcess = settingsUI.filesToProcess.selectedValuesList - userSettings.filesToProcess = - settingsUI.filesToProcess.items.filter { path -> settingsUI.filesToProcess.isItemSelected(path) } - } - } -} - -private val CheckBoxList.items: List - get() { - val items = mutableListOf() - for (i in 0 until model.size) { - items.add(getItemAt(i)!!) - } - return items - } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateDocumentationAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateDocumentationAction.kt new file mode 100644 index 00000000..32dbe825 --- /dev/null +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateDocumentationAction.kt @@ -0,0 +1,236 @@ +package com.github.simiacryptus.aicoder.actions.generic + +import com.github.simiacryptus.aicoder.actions.FileContextAction +import com.github.simiacryptus.aicoder.config.AppSettingsState +import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel +import com.github.simiacryptus.aicoder.config.Name +import com.github.simiacryptus.aicoder.util.UITools +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.ui.CheckBoxList +import com.intellij.ui.components.JBScrollPane +import com.intellij.ui.components.JBTextArea +import com.intellij.ui.components.JBTextField +import com.simiacryptus.jopenai.ApiModel +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import org.apache.commons.io.IOUtils +import java.awt.BorderLayout +import java.awt.Dimension +import java.io.File +import java.io.FileInputStream +import java.nio.file.Files +import java.nio.file.Path +import java.util.concurrent.Executors +import java.util.concurrent.Future +import java.util.concurrent.TimeUnit +import javax.swing.BoxLayout +import javax.swing.JComponent +import javax.swing.JLabel +import javax.swing.JPanel + + +class GenerateDocumentationAction : FileContextAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent): Boolean { + if (UITools.getSelectedFile(event)?.isDirectory == false) return false + return super.isEnabled(event) + } + + class SettingsUI { + @Name("Files to Process") + val filesToProcess = CheckBoxList() + + @Name("AI Instruction") + val transformationMessage = JBTextArea(4, 40) + + @Name("Output File") + val outputFilename = JBTextField() + } + + class UserSettings( + var transformationMessage: String = "Create user documentation", + var outputFilename: String = "compiled_documentation.md", + var filesToProcess: List = listOf(), + ) + + class Settings( + val settings: UserSettings? = null, + val project: Project? = null + ) + + override fun getConfig(project: Project?, e: AnActionEvent): Settings { + val root = UITools.getSelectedFolder(e)?.toNioPath() + val files = Files.walk(root) + .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } + .toList().filterNotNull().toTypedArray() + val settingsUI = SettingsUI().apply { + filesToProcess.setItems(files.toMutableList()) { path -> + root?.relativize(path)?.toString() ?: path.toString() + } + files.forEach { path -> + filesToProcess.setItemSelected(path, true) + } + } + val dialog = DocumentationCompilerDialog(project, settingsUI) + dialog.show() + val result = dialog.isOK + val settings: UserSettings = dialog.userSettings + settings.filesToProcess = when { + result -> files.filter { path -> settingsUI.filesToProcess.isItemSelected(path) }.toList() + else -> listOf() + } + //.map { path -> return@map root?.resolve(path) }.filterNotNull() + return Settings(settings, project) + } + + override fun processSelection(state: SelectionState, config: Settings?): Array { + val root = state.selectedFile.toPath() + var outputPath = root.resolve(config?.settings?.outputFilename ?: "compiled_documentation.md") + if (outputPath.toFile().exists()) { + val extension = outputPath.toString().split(".").last() + val name = outputPath.toString().split(".").dropLast(1).joinToString(".") + val fileIndex = (1..Int.MAX_VALUE).find { + !root.resolve("$name.$it.$extension").toFile().exists() + } + outputPath = root.resolve("$name.$fileIndex.$extension") + } + val executorService = Executors.newFixedThreadPool(4) + outputPath.parent.toFile().mkdirs() + val transformationMessage = config?.settings?.transformationMessage ?: "Create user documentation" + val markdownContent = StringBuilder() + try { + val selectedPaths = config?.settings?.filesToProcess ?: listOf() + val partitionedPaths = Files.walk(root) + .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } + .toList().groupBy { selectedPaths.contains(it) } + val pathList = partitionedPaths[true]!! + .toList().filterNotNull() + .map> { path -> + executorService.submit { + val fileContent = + IOUtils.toString(FileInputStream(path.toFile()), "UTF-8") ?: return@submit null + val transformContent = transformContent(fileContent, transformationMessage) + markdownContent.append("# ${root.relativize(path)}\n\n") + markdownContent.append(transformContent.replace("(?s)(? + try { + future.get() ?: return@map null + } catch (e: Exception) { + log.warn("Error processing file", e) + return@map null + } + }.filterNotNull() + Files.write(outputPath, markdownContent.toString().toByteArray()) + open(config?.project!!, outputPath) + return arrayOf(outputPath.toFile()) + } finally { + executorService.shutdown() + } + } + + private fun transformContent(fileContent: String, transformationMessage: String) = api.chat( + ApiModel.ChatRequest( + model = AppSettingsState.instance.smartModel.chatModel().modelName, + temperature = AppSettingsState.instance.temperature, + messages = listOf( + ApiModel.ChatMessage( + ApiModel.Role.system, """ + You will combine natural language instructions with a user provided code example to document code. + """.trimIndent().toContentList(), null + ), + ApiModel.ChatMessage(ApiModel.Role.user, fileContent.toContentList()), + ApiModel.ChatMessage(ApiModel.Role.user, transformationMessage.toContentList()), + ), + ), + AppSettingsState.instance.smartModel.chatModel() + ).choices.first().message?.content?.trim() ?: fileContent + + companion object { + private val scheduledPool = Executors.newScheduledThreadPool(1) + fun open(project: Project, outputPath: Path) { + lateinit var function: () -> Unit + function = { + val file = outputPath.toFile() + if (file.exists()) { + // Ensure the IDE is ready for file operations + ApplicationManager.getApplication().invokeLater { + val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) + if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { + val localFileSystem = LocalFileSystem.getInstance() + // Refresh the file system to ensure the file is visible + val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) + virtualFile?.let { + FileEditorManager.getInstance(project).openFile(it, true) + } ?: scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } else { + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + } else { + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + + class DocumentationCompilerDialog(project: Project?, private val settingsUI: SettingsUI) : DialogWrapper(project) { + val userSettings = UserSettings() + + init { + title = "Compile Documentation" + // Set the default values for the UI elements from userSettings + settingsUI.transformationMessage.text = userSettings.transformationMessage + settingsUI.outputFilename.text = userSettings.outputFilename + init() + } + + override fun createCenterPanel(): JComponent { + val panel = JPanel(BorderLayout()).apply { + val filesScrollPane = JBScrollPane(settingsUI.filesToProcess).apply { + preferredSize = Dimension(400, 300) // Adjust the preferred size as needed + } + add(JLabel("Files to Process"), BorderLayout.NORTH) + add(filesScrollPane, BorderLayout.CENTER) // Make the files list the dominant element + + val optionsPanel = JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + add(JLabel("AI Instruction")) + add(settingsUI.transformationMessage) + add(JLabel("Output File")) + add(settingsUI.outputFilename) + } + add(optionsPanel, BorderLayout.SOUTH) + } + return panel + } + + override fun doOKAction() { + super.doOKAction() + userSettings.transformationMessage = settingsUI.transformationMessage.text + userSettings.outputFilename = settingsUI.outputFilename.text + // Assuming filesToProcess already reflects the user's selection +// userSettings.filesToProcess = settingsUI.filesToProcess.selectedValuesList + userSettings.filesToProcess = + settingsUI.filesToProcess.items.filter { path -> settingsUI.filesToProcess.isItemSelected(path) } + } + } +} + +private val CheckBoxList.items: List + get() { + val items = mutableListOf() + for (i in 0 until model.size) { + items.add(getItemAt(i)!!) + } + return items + } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateRelatedFileAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateRelatedFileAction.kt new file mode 100644 index 00000000..59dad47c --- /dev/null +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateRelatedFileAction.kt @@ -0,0 +1,158 @@ +package com.github.simiacryptus.aicoder.actions.generic + +import com.github.simiacryptus.aicoder.actions.FileContextAction +import com.github.simiacryptus.aicoder.config.AppSettingsState +import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel +import com.github.simiacryptus.aicoder.util.UITools +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.LocalFileSystem +import com.simiacryptus.jopenai.ApiModel +import com.simiacryptus.jopenai.ApiModel.ChatMessage +import com.simiacryptus.jopenai.ApiModel.Role +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import org.apache.commons.io.FileUtils +import org.apache.commons.io.IOUtils +import java.io.File +import java.io.FileInputStream +import java.nio.file.Path +import java.util.concurrent.TimeUnit + +class GenerateRelatedFileAction : FileContextAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + override fun isEnabled(event: AnActionEvent): Boolean { + if (UITools.getSelectedFile(event)?.isDirectory == true) return false + return super.isEnabled(event) + } + + data class ProjectFile( + val path: String = "", + val code: String = "" + ) + + class SettingsUI + + class UserSettings( + var directive: String = "", + ) + + class Settings( + val settings: UserSettings? = null, + val project: Project? = null + ) + + override fun getConfig(project: Project?, e: AnActionEvent): Settings { + return Settings( + UITools.showDialog( + project, + SettingsUI::class.java, + UserSettings::class.java, + "Create Analogue File" + ), project + ) + } + + override fun processSelection(state: SelectionState, config: Settings?): Array { + val root = getModuleRootForFile(state.selectedFile).toPath() + val selectedFile = state.selectedFile + val analogue = generateFile( + ProjectFile( + path = root.relativize(selectedFile.toPath()).toString(), + code = IOUtils.toString(FileInputStream(selectedFile), "UTF-8") + ), + config?.settings?.directive ?: "" + ) + var outputPath = root.resolve(analogue.path) + if (outputPath.toFile().exists()) { + val extension = outputPath.toString().split(".").last() + val name = outputPath.toString().split(".").dropLast(1).joinToString(".") + val fileIndex = (1..Int.MAX_VALUE).find { + !root.resolve("$name.$it.$extension").toFile().exists() + } + outputPath = root.resolve("$name.$fileIndex.$extension") + } + outputPath.parent.toFile().mkdirs() + FileUtils.write(outputPath.toFile(), analogue.code, "UTF-8") + open(config?.project!!, outputPath) + return arrayOf(outputPath.toFile()) + } + + private fun generateFile(baseFile: ProjectFile, directive: String): ProjectFile { + val model = AppSettingsState.instance.smartModel.chatModel() + val chatRequest = ApiModel.ChatRequest( + model = model.modelName, + temperature = AppSettingsState.instance.temperature, + messages = listOf( + ChatMessage( + Role.system, """ + You will combine natural language instructions with a user provided code example to create a new file. + Provide a new filename and the code to be written to the file. + Paths should be relative to the project root and should not exist. + Output the file path using the a line with the format "File: ". + Output the file code directly after the header line with no additional decoration. + """.trimIndent().toContentList(), null + ), + ChatMessage( + Role.user, """ + |Create a new file based on the following directive: $directive + | + |The file should be based on `${baseFile.path}` which contains the following code: + | + |``` + |${baseFile.code.let { /*escapeHtml4*/it/*.indent(" ")*/ }} + |``` + """.trimMargin().toContentList(), null + ) + + ) + ) + val response = api.chat(chatRequest, model).choices.first().message?.content?.trim() + var outputPath = baseFile.path + val header = response?.split("\n")?.first() + var body = response?.split("\n")?.drop(1)?.joinToString("\n")?.trim() + if (body?.contains("```") == true) { + body = body.split("```.*".toRegex()).drop(1).firstOrNull()?.trim() ?: body + } + val pathPattern = "File(?:name)?: ['\"]?([^'\"]+)['\"]?".toRegex() + val matcher = pathPattern.find(header ?: "") + if (matcher != null) { + outputPath = matcher.groupValues[1].trim() + } + return ProjectFile( + path = outputPath, + code = body ?: "" + ) + } + + companion object { + fun open(project: Project, outputPath: Path) { + lateinit var function: () -> Unit + function = { + val file = outputPath.toFile() + if (file.exists()) { + // Ensure the IDE is ready for file operations + ApplicationManager.getApplication().invokeLater { + val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) + if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { + val localFileSystem = LocalFileSystem.getInstance() + // Refresh the file system to ensure the file is visible + val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) + virtualFile?.let { + FileEditorManager.getInstance(project).openFile(it, true) + } ?: scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } else { + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + } else { + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + + } +} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenericChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenericChatAction.kt new file mode 100644 index 00000000..c6cd39de --- /dev/null +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenericChatAction.kt @@ -0,0 +1,83 @@ +package com.github.simiacryptus.aicoder.actions.generic + +import com.github.simiacryptus.aicoder.AppServer +import com.github.simiacryptus.aicoder.actions.BaseAction +import com.github.simiacryptus.aicoder.config.AppSettingsState +import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel +import com.github.simiacryptus.aicoder.util.CodeChatSocketManager +import com.github.simiacryptus.aicoder.util.ComputerLanguage +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.StorageInterface +import com.simiacryptus.skyenet.core.platform.User +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.chat.ChatServer +import com.simiacryptus.skyenet.webui.chat.ChatSocketManager +import com.simiacryptus.skyenet.webui.session.SocketManager +import org.slf4j.LoggerFactory +import java.awt.Desktop +import java.io.File + +class GenericChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + val path = "/codeChat" + val systemPrompt = "" + val userInterfacePrompt = "" + val model = AppSettingsState.instance.smartModel.chatModel() + + override fun handle(e: AnActionEvent) { + val session = StorageInterface.newGlobalID() + agents[session] = ChatSocketManager( + session = session, + model = model, + initialAssistantPrompt = "", + userInterfacePrompt = userInterfacePrompt, + systemPrompt = systemPrompt, + api = api, + storage = ApplicationServices.dataStorageFactory(root), + applicationClass = ApplicationServer::class.java, + ) + + val server = AppServer.getServer(e.project) + val app = initApp(server, path) + app.sessions[session] = app.newSession(null, session) + + Thread { + Thread.sleep(500) + try { + Desktop.getDesktop().browse(server.server.uri.resolve("$path/#$session")) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + override fun isEnabled(event: AnActionEvent) = true + + companion object { + private val log = LoggerFactory.getLogger(CodeChatAction::class.java) + private val agents = mutableMapOf() + val root: File get() = File(AppSettingsState.instance.pluginHome, "code_chat") + private fun initApp(server: AppServer, path: String): ChatServer { + server.appRegistry[path]?.let { return it } + val socketServer = object : ApplicationServer( + applicationName = "Code Chat", + path = path, + showMenubar = false, + ) { + override val singleInput = false + override val stickyInput = true + override fun newSession(user: User?, session: Session) = + agents[session] ?: throw IllegalArgumentException("Unknown session: $session") + } + server.addApp(path, socketServer) + return socketServer + } + + } +} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiDiffChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiDiffChatAction.kt index a8d844a4..50b0478a 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiDiffChatAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiDiffChatAction.kt @@ -1,16 +1,15 @@ package com.github.simiacryptus.aicoder.actions.generic import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.dev.AppServer +import com.github.simiacryptus.aicoder.AppServer import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.ComputerLanguage import com.github.simiacryptus.aicoder.util.UITools import com.github.simiacryptus.diff.addApplyFileDiffLinks +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.command.WriteCommandAction -import com.intellij.openapi.fileEditor.FileDocumentManager import com.simiacryptus.skyenet.core.platform.ApplicationServices import com.simiacryptus.skyenet.core.platform.Session import com.simiacryptus.skyenet.core.platform.StorageInterface @@ -25,8 +24,10 @@ import com.simiacryptus.skyenet.webui.util.MarkdownUtil.renderMarkdown import org.slf4j.LoggerFactory import java.awt.Desktop import java.io.File +import java.nio.file.Path class MultiDiffChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT val path = "/multiDiffChat" @@ -34,10 +35,7 @@ class MultiDiffChatAction : BaseAction() { val dataContext = e.dataContext val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) - val languages = - virtualFiles?.associate { it to ComputerLanguage.findByExtension(it.extension ?: "")?.name } ?: mapOf() - val virtualFileMap = virtualFiles?.associate { it.toNioPath() to it } ?: mapOf() - val codeFiles = mutableMapOf() + val codeFiles = mutableMapOf() val folder = UITools.getSelectedFolder(e) val root = if (null != folder) { folder.toFile.toPath() @@ -45,23 +43,20 @@ class MultiDiffChatAction : BaseAction() { getModuleRootForFile(UITools.getSelectedFile(e)?.parent?.toFile ?: throw RuntimeException("")).toPath() } -// val root = virtualFiles?.map { file -> -// file.toNioPath() -// }?.toTypedArray()?.commonRoot()!! - - virtualFiles?.associate { file -> + virtualFiles?.forEach { file -> val relative = root.relativize(file.toNioPath()) - val path = relative.toString() - val language = languages[file] ?: "plaintext" - val code = file.contentsToByteArray().toString(Charsets.UTF_8) - codeFiles[path] = code - path to language + val path = relative + codeFiles[path] = file.contentsToByteArray().toString(Charsets.UTF_8) } fun codeSummary() = codeFiles.entries.joinToString("\n\n") { (path, code) -> - "# $path\n```${ - path.split('.').lastOrNull()?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ } - }\n${code?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }}\n```" + val extension = path.toString().split('.').lastOrNull()?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ } + """ + |# $path + |```$extension + |${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} + |``` + """.trimMargin() } val session = StorageInterface.newGlobalID() @@ -72,34 +67,34 @@ class MultiDiffChatAction : BaseAction() { session = session, model = AppSettingsState.instance.smartModel.chatModel(), userInterfacePrompt = """ - | - |$codeSummary - | - """.trimMargin().trim(), + | + |$codeSummary + | + """.trimMargin().trim(), systemPrompt = """ - You are a helpful AI that helps people with coding. - - You will be answering questions about the following code: - - $codeSummary - - Response should use one or more code patches in diff format within ```diff code blocks. - Each diff should be preceded by a header that identifies the file being modified. - The diff format should use + for line additions, - for line deletions. - The diff should include 2 lines of context before and after every change. - - Example: - - Explanation text - - ### scripts/filename.js - ```diff - - const b = 2; - + const a = 1; - ``` - - Continued text - """.trimIndent(), + |You are a helpful AI that helps people with coding. + | + |You will be answering questions about the following code: + | + |$codeSummary + | + |Response should use one or more code patches in diff format within ```diff code blocks. + |Each diff should be preceded by a header that identifies the file being modified. + |The diff format should use + for line additions, - for line deletions. + |The diff should include 2 lines of context before and after every change. + | + |Example: + | + |Explanation text + | + |### scripts/filename.js + |```diff + |- const b = 2; + |+ const a = 1; + |``` + | + |Continued text + """.trimMargin(), api = api, applicationClass = ApplicationServer::class.java, storage = ApplicationServices.dataStorageFactory(DiffChatAction.root), @@ -108,28 +103,11 @@ class MultiDiffChatAction : BaseAction() { override fun renderResponse(response: String, task: SessionTask): String { val html = addApplyFileDiffLinks( root = root, - code = codeFiles, + code = { codeFiles }, response = response, handle = { newCodeMap -> - newCodeMap.map { (path, newCode) -> - val prev = codeFiles[path] - if (prev != newCode) { - codeFiles[path] = newCode - root.resolve(path).let { file -> - file.toFile().writeText(newCode) - val virtualFile = virtualFileMap.get(file) - if (null != virtualFile) FileDocumentManager.getInstance().getDocument(virtualFile) - ?.let { doc -> - WriteCommandAction.runWriteCommandAction(e.project) { - doc.setText(newCode) - } - } - } - "$path Updated" - } else { -// "$path Unchanged" - "" - } + newCodeMap.forEach { (path, newCode) -> + task.complete("$path Updated") } }, ui = ui, @@ -165,8 +143,8 @@ class MultiDiffChatAction : BaseAction() { path = path, showMenubar = false, ) { - override val singleInput = false - override val stickyInput = true + override val singleInput = true + override val stickyInput = false override fun newSession(user: User?, session: Session) = agents[session]!! } server.addApp(path, socketServer) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiStepPatchAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiStepPatchAction.kt new file mode 100644 index 00000000..1ed3801e --- /dev/null +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiStepPatchAction.kt @@ -0,0 +1,300 @@ +package com.github.simiacryptus.aicoder.actions.generic + +import com.github.simiacryptus.aicoder.actions.BaseAction +import com.github.simiacryptus.aicoder.AppServer +import com.github.simiacryptus.aicoder.config.AppSettingsState +import com.github.simiacryptus.aicoder.util.UITools +import com.github.simiacryptus.diff.addApplyFileDiffLinks +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ApiModel +import com.simiacryptus.jopenai.ApiModel.Role +import com.simiacryptus.jopenai.describe.Description +import com.simiacryptus.jopenai.models.ChatModels +import com.simiacryptus.jopenai.proxy.ValidatedObject +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import com.simiacryptus.jopenai.util.JsonUtil.toJson +import com.simiacryptus.skyenet.Acceptable +import com.simiacryptus.skyenet.AgentPatterns +import com.simiacryptus.skyenet.core.actors.* +import com.simiacryptus.skyenet.core.platform.* +import com.simiacryptus.skyenet.core.platform.file.DataStorage +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.chat.ChatServer +import com.simiacryptus.skyenet.webui.util.MarkdownUtil.renderMarkdown +import org.slf4j.LoggerFactory +import java.awt.Desktop +import java.io.File +import java.nio.file.Path +import java.util.concurrent.Semaphore +import java.util.concurrent.atomic.AtomicReference + +class MultiStepPatchAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + val path = "/autodev" + + override fun handle(e: AnActionEvent) { + val session = StorageInterface.newGlobalID() + val storage = ApplicationServices.dataStorageFactory(DiffChatAction.root) as DataStorage? + val selectedFile = UITools.getSelectedFolder(e) + if (null != storage && null != selectedFile) { + DataStorage.sessionPaths[session] = selectedFile.toFile + } + agents[session] = AutoDevApp(event = e) + val server = AppServer.getServer(e.project) + val app = initApp(server, path) + app.sessions[session] = app.newSession(null, session) + Thread { + Thread.sleep(500) + try { + Desktop.getDesktop().browse(server.server.uri.resolve("$path/#$session")) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + open class AutoDevApp( + applicationName: String = "Auto Dev Assistant v1.1", + val temperature: Double = 0.1, + val event: AnActionEvent, + ) : ApplicationServer( + applicationName = applicationName, + path = "/autodev", + showMenubar = false, + ) { + override fun userMessage( + session: Session, + user: User?, + userMessage: String, + ui: ApplicationInterface, + api: API + ) { + val settings = getSettings(session, user) ?: Settings() + if (api is ClientManager.MonitoredClient) api.budget = settings.budget ?: 2.00 + AutoDevAgent( + api = api, + dataStorage = dataStorage, + session = session, + user = user, + ui = ui, + model = settings.model!!, + parsingModel = AppSettingsState.instance.defaultFastModel(), + event = event, + ).start( + userMessage = userMessage, + ) + } + + data class Settings( + val budget: Double? = 2.00, + val tools: List = emptyList(), + val model: ChatModels? = AppSettingsState.instance.defaultSmartModel(), + ) + + override val settingsClass: Class<*> get() = Settings::class.java + + @Suppress("UNCHECKED_CAST") + override fun initSettings(session: Session): T? = Settings() as T + } + + class AutoDevAgent( + val api: API, + dataStorage: StorageInterface, + session: Session, + user: User?, + val ui: ApplicationInterface, + val model: ChatModels, + val parsingModel: ChatModels, + actorMap: Map> = mapOf( + ActorTypes.DesignActor to ParsedActor( + resultClass = TaskList::class.java, + prompt = """ + Translate the user directive into an action plan for the project. + Break the user's request into a list of simple tasks to be performed. + For each task, provide a list of files to be modified and a description of the changes to be made. + """.trimIndent(), + model = model, + parsingModel = parsingModel, + ), + ActorTypes.TaskCodingActor to SimpleActor( + prompt = """ + Implement the changes to the codebase as described in the task list. + + Response should use one or more code patches in diff format within ```diff code blocks. + Each diff should be preceded by a header that identifies the file being modified. + The diff format should use + for line additions, - for line deletions. + The diff should include 2 lines of context before and after every change. + + Example: + + Explanation text + + ### scripts/filename.js + ```diff +import com.simiacryptus.skyenet.webui.components.CheckboxTab + - const b = 2; + + const a = 1; + ``` + + Continued text + """.trimIndent(), + model = model + ), + ), + val event: AnActionEvent, + ) : ActorSystem( + actorMap.map { it.key.name to it.value }.toMap(), dataStorage, user, session + ) { + enum class ActorTypes { + DesignActor, + TaskCodingActor, + } + + private val designActor by lazy { getActor(ActorTypes.DesignActor) as ParsedActor } + private val taskActor by lazy { getActor(ActorTypes.TaskCodingActor) as SimpleActor } + + fun start( + userMessage: String, + ) { + val codeFiles = mutableMapOf() + val root = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext) + ?.map { it.toFile.toPath() }?.toTypedArray()?.commonRoot()!! + PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext)?.forEach { file -> + val code = file.inputStream.bufferedReader().use { it.readText() } + codeFiles[root.relativize(file.toNioPath())] = code + } + require(codeFiles.isNotEmpty()) { "No files selected" } + fun codeSummary() = codeFiles.entries.joinToString("\n\n") { (path, code) -> + "# $path\n```${ + path.toString().split('.').last() + }\n${code/*.indent(" ")*/}\n```" + } + + val task = ui.newTask() + val toInput = { it: String -> listOf(codeSummary(), it) } + val architectureResponse = Acceptable( + task = task, + userMessage = userMessage, + initialResponse = { it: String -> designActor.answer(toInput(it), api = api) }, + outputFn = { design: ParsedResponse -> + // renderMarkdown("${design.text}\n\n```json\n${JsonUtil.toJson(design.obj)/*.indent(" ")*/}\n```") + AgentPatterns.displayMapInTabs( + mapOf( + "Text" to renderMarkdown(design.text, ui = ui), + "JSON" to renderMarkdown("```json\n${toJson(design.obj)/*.indent(" ")*/}\n```", ui = ui), + ) + ) + }, + ui = ui, + reviseResponse = { userMessages: List> -> + designActor.respond( + messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } + .toTypedArray()), + input = toInput(userMessage), + api = api + ) + }, + atomicRef = AtomicReference(), + semaphore = Semaphore(0), + heading = userMessage + ).call() + + try { + architectureResponse.obj.tasks.forEach { (paths, description) -> + task.complete(ui.hrefLink(renderMarkdown("Task: $description", ui = ui)) { + val task = ui.newTask() + task.header("Task: $description") + val process = { it: StringBuilder -> + val filter = codeFiles.filter { (path, _) -> + paths?.find { path.toString().contains(it) }?.isNotEmpty() == true + } + require(filter.isNotEmpty()) { + """ + |No files found for $paths + | + |Root: + |$root + | + |Files: + |${codeFiles.keys.joinToString("\n")} + | + |Paths: + |${paths?.joinToString("\n") ?: ""} + | + """.trimMargin() + } + ui.socketManager.addApplyFileDiffLinks( + root = root, + code = { codeFiles }, + response = taskActor.answer(listOf( + codeSummary(), + userMessage, + filter.entries.joinToString("\n\n") { + "# ${it.key}\n```${ + it.key.toString().split('.').last()?.let { /*escapeHtml4*/it/*.indent(" ")*/ } + }\n${it.value/*.indent(" ")*/}\n```" + }, + architectureResponse.text, + "Provide a change for ${paths?.joinToString(",") { it } ?: ""} ($description)" + ), api), + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + task.complete("$path Updated") + } + }, + ui = ui + ) + } + }) + } + } catch (e : Exception) { + log.warn("Error",e) + } + } + } + companion object { + private val log = LoggerFactory.getLogger(MultiStepPatchAction::class.java) + private val agents = mutableMapOf() + val root: File get() = File(AppSettingsState.instance.pluginHome, "code_chat") + private fun initApp(server: AppServer, path: String): ChatServer { + server.appRegistry[path]?.let { return it } + val socketServer = object : ApplicationServer(applicationName = "Code Chat", path = path) { + override val singleInput = true + override val stickyInput = false + override fun newSession(user: User?, session: Session) = agents[session]!!.newSession(user, session) + } + server.addApp(path, socketServer) + return socketServer + } + + data class TaskList( + @Description("List of tasks to be performed in this project") + val tasks: List = emptyList() + ) : ValidatedObject { + override fun validate(): String? = when { + tasks.isEmpty() -> "Resources are required" + tasks.any { it.validate() != null } -> "Invalid resource" + else -> null + } + } + + data class Task( + @Description("List of paths involved in the task. This should include all files to be modified, and can include other files whose content will be informative in writing the changes.") + val paths: List? = null, + @Description("Detailed description of the changes to be made. Markdown format is supported.") + val description: String? = null + ) : ValidatedObject { + override fun validate(): String? = when { + paths.isNullOrEmpty() -> "Paths are required" + paths.any { it.isBlank() } -> "Invalid path" + else -> null + } + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/TaskRunnerAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/PlanAheadAction.kt similarity index 96% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/TaskRunnerAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/PlanAheadAction.kt index 3c3926cc..44765132 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/TaskRunnerAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/PlanAheadAction.kt @@ -1,12 +1,13 @@ package com.github.simiacryptus.aicoder.actions.generic import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.dev.AppServer +import com.github.simiacryptus.aicoder.AppServer import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.UITools import com.github.simiacryptus.diff.addApplyFileDiffLinks import com.github.simiacryptus.diff.addSaveLinks +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.PlatformDataKeys.VIRTUAL_FILE_ARRAY import com.intellij.openapi.vfs.VirtualFile @@ -47,7 +48,8 @@ import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.atomic.AtomicReference import kotlin.reflect.KClass -class TaskRunnerAction : BaseAction() { +class PlanAheadAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT val path = "/taskDev" override fun handle(e: AnActionEvent) { @@ -96,7 +98,7 @@ class TaskRunnerApp( override val settingsClass: Class<*> get() = Settings::class.java @Suppress("UNCHECKED_CAST") - override fun initSettings(session: Session): T? = Settings() as T + override fun initSettings(session: Session): T = Settings() as T override fun userMessage( session: Session, @@ -306,10 +308,10 @@ class TaskRunnerAgent( Note: This task is for running simple and safe commands. Avoid executing commands that can cause harm to the system or compromise security. """.trimIndent(), symbols = mapOf( - "env" to (env ?: mapOf()), - "workingDir" to File(workingDir ?: ".").absolutePath, - "language" to (language ?: "bash"), - "command" to (command ?: listOf("bash")), + "env" to env, + "workingDir" to File(workingDir).absolutePath, + "language" to language, + "command" to command, ), model = model, temperature = temperature, @@ -380,16 +382,19 @@ class TaskRunnerAgent( }.toTypedArray() } - val codeFiles = mutableMapOf().apply { - virtualFiles.filter { it.isFile }.forEach { file -> - val code = file.inputStream.bufferedReader().use { it.readText() } - this[root.relativize(file.toNioPath()).toString()] = code + private val codeFiles + get() = virtualFiles.filter { it.isFile }.associate { file -> + getKey(file) to getValue(file) } - } + + + private fun getValue(file: VirtualFile) = file.inputStream.bufferedReader().use { it.readText() } + + private fun getKey(file: VirtualFile) = root.relativize(file.toNioPath()) fun startProcess(userMessage: String) { val codeFiles = codeFiles - val eventStatus = if (!codeFiles.all { File(it.key).isFile } || codeFiles.size > 2) """ + val eventStatus = if (!codeFiles.all { it.key.toFile().isFile } || codeFiles.size > 2) """ |Files: |${codeFiles.keys.joinToString("\n") { "* ${it}" }} """.trimMargin() else { @@ -400,7 +405,7 @@ class TaskRunnerAgent( """ |## $path | - |${(codeFiles[path.toString()] ?: "").let { "```\n${it/*.indent(" ")*/}\n```" }} + |${(codeFiles[path] ?: "").let { "```\n${it/*.indent(" ")*/}\n```" }} """.trimMargin() } } @@ -573,7 +578,7 @@ class TaskRunnerAgent( |# $it | |``` - |${codeFiles[it] ?: root.resolve(it).toFile().readText()} + |${codeFiles[File(it).toPath()] ?: root.resolve(it).toFile().readText()} |``` """.trimMargin() } catch (e: Throwable) { @@ -838,7 +843,7 @@ class TaskRunnerAgent( if (prev != newCode) { // codeFiles[path] = newCode val bytes = newCode.toByteArray(Charsets.UTF_8) - val saveFile = task.saveFile(path, bytes) + val saveFile = task.saveFile(path.toString(), bytes) task.complete("$path Created") } else { task.complete("No changes to $path") @@ -851,7 +856,7 @@ class TaskRunnerAgent( } object : Retryable(ui, task, process) { init { - set(label(size), process(container!!)) + set(label(size), process(container)) } } } @@ -882,23 +887,11 @@ class TaskRunnerAgent( renderMarkdown( ui.socketManager.addApplyFileDiffLinks( root = root, - code = codeFiles, + code = { codeFiles }, response = codeResult, handle = { newCodeMap -> - val codeFiles = codeFiles newCodeMap.forEach { (path, newCode) -> - val prev = codeFiles[path] - if (prev != newCode) { -// codeFiles[path] = newCode - task.complete( - "$path Updated" - ) - } + task.complete("$path Updated") } }, ui = ui @@ -912,7 +905,7 @@ class TaskRunnerAgent( } object : Retryable(ui, task, process) { init { - set(label(size), process(container!!)) + set(label(size), process(container)) } } } @@ -947,7 +940,7 @@ class TaskRunnerAgent( } object : Retryable(ui, task, process) { init { - set(label(size), process(container!!)) + set(label(size), process(container)) } } } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/WebDevAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/WebDevelopmentAssistantAction.kt similarity index 91% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/WebDevAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/WebDevelopmentAssistantAction.kt index bfc75831..11f19be9 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/WebDevAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/WebDevelopmentAssistantAction.kt @@ -1,10 +1,11 @@ package com.github.simiacryptus.aicoder.actions.generic import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.dev.AppServer +import com.github.simiacryptus.aicoder.AppServer import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.util.UITools import com.github.simiacryptus.diff.addApplyFileDiffLinks +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.vfs.VirtualFile import com.simiacryptus.jopenai.API @@ -29,13 +30,15 @@ import com.simiacryptus.skyenet.webui.util.MarkdownUtil.renderMarkdown import org.slf4j.LoggerFactory import java.awt.Desktop import java.io.File +import java.nio.file.Path import java.util.concurrent.Semaphore import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicReference val VirtualFile.toFile: File get() = File(this.path) -class WebDevAction : BaseAction() { +class WebDevelopmentAssistantAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT val path = "/webDev" @@ -67,7 +70,6 @@ class WebDevAction : BaseAction() { open class WebDevApp( applicationName: String = "Web Dev Assistant v1.1", - open val symbols: Map = mapOf(), val temperature: Double = 0.1, ) : ApplicationServer( applicationName = applicationName, @@ -202,7 +204,7 @@ class WebDevAction : BaseAction() { private val codeReviewer by lazy { getActor(ActorTypes.CodeReviewer) as SimpleActor } private val etcActor by lazy { getActor(ActorTypes.EtcCodingActor) as SimpleActor } - private val codeFiles = mutableMapOf() + private val codeFiles = mutableMapOf() fun start( userMessage: String, @@ -266,7 +268,7 @@ class WebDevAction : BaseAction() { ) ), javascriptActor, - path!!, "js", "javascript" + File(path).toPath(), "js", "javascript" ) @@ -280,7 +282,7 @@ class WebDevAction : BaseAction() { ) ), cssActor, - path + File(path).toPath() ) "html" -> draftResourceCode( @@ -293,7 +295,7 @@ class WebDevAction : BaseAction() { ) ), htmlActor, - path + File(path).toPath() ) else -> draftResourceCode( @@ -305,7 +307,8 @@ class WebDevAction : BaseAction() { "Render $path - $description" ) ), - etcActor, path + etcActor, + File(path).toPath() ) } @@ -313,8 +316,8 @@ class WebDevAction : BaseAction() { // Apply codeReviewer fun codeSummary() = codeFiles.entries.joinToString("\n\n") { (path, code) -> "# $path\n```${ - path.split('.').last()?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ } - }\n${code?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }}\n```" + path.toString().split('.').last().let { /*escapeHtml4*/(it)/*.indent(" ")*/ } + }\n${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }}\n```" } @@ -322,23 +325,12 @@ class WebDevAction : BaseAction() { //val task = ui.newTask() return task.complete( ui.socketManager.addApplyFileDiffLinks( - root = codeFiles.keys.map { File(it).toPath() }.toTypedArray().commonRoot(), - code = codeFiles, + root = codeFiles.keys.map { it }.toTypedArray().commonRoot(), + code = { codeFiles }, response = design, handle = { newCodeMap -> newCodeMap.forEach { (path, newCode) -> - val prev = codeFiles[path] - if (prev != newCode) { - codeFiles[path] = newCode - task.complete( - "$path Updated" - ) - } + task.complete("$path Updated") } }, ui = ui @@ -391,8 +383,8 @@ class WebDevAction : BaseAction() { task: SessionTask, request: Array, actor: SimpleActor, - path: String, - vararg languages: String = arrayOf(path.split(".").last().lowercase()), + path: Path, + vararg languages: String = arrayOf(path.toString().split(".").last().lowercase()), ) { try { var code = actor.respond(emptyList(), api, *request) @@ -402,15 +394,15 @@ class WebDevAction : BaseAction() { try { task.add( renderMarkdown( - "```${languages.first()}\n${code?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }}\n```", + "```${languages.first()}\n${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }}\n```", ui = ui ) ) - task.add("$path Updated") + task.add("$path Updated") codeFiles[path] = code val request1 = (request.toList() + listOf( - ApiModel.ChatMessage(ApiModel.Role.assistant, code.toContentList()), + ApiModel.ChatMessage(Role.assistant, code.toContentList()), )).toTypedArray() val formText = StringBuilder() var formHandle: StringBuilder? = null @@ -423,7 +415,7 @@ class WebDevAction : BaseAction() { responseAction(task, "Regenerating...", formHandle!!, formText) { draftResourceCode( task, - request1.dropLastWhile { it.role == ApiModel.Role.assistant } + request1.dropLastWhile { it.role == Role.assistant } .toTypedArray(), actor, path, *languages ) @@ -439,8 +431,8 @@ class WebDevAction : BaseAction() { task.echo(renderMarkdown(feedback, ui = ui)) draftResourceCode( task, (request1.toList() + listOf( - code to ApiModel.Role.assistant, - feedback to ApiModel.Role.user, + code to Role.assistant, + feedback to Role.user, ).filter { it.first.isNotBlank() } .map { ApiModel.ChatMessage( @@ -504,7 +496,7 @@ class WebDevAction : BaseAction() { } companion object { - private val log = LoggerFactory.getLogger(WebDevAction::class.java) + private val log = LoggerFactory.getLogger(WebDevelopmentAssistantAction::class.java) private val agents = mutableMapOf() val root: File get() = File(AppSettingsState.instance.pluginHome, "code_chat") private fun initApp(server: AppServer, path: String): ChatServer { diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/PrintGitCommitPatchAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/PrintGitCommitPatchAction.kt deleted file mode 100644 index 69f1b2e7..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/PrintGitCommitPatchAction.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.git - -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.Messages -import com.intellij.openapi.vcs.VcsDataKeys -import com.intellij.openapi.vcs.changes.Change -import com.intellij.openapi.vcs.changes.ChangeListManager -import com.intellij.openapi.vcs.history.VcsRevisionNumber - -class PrintGitCommitPatchAction : AnAction("Print Git Commit Patch") { - - override fun actionPerformed(event: AnActionEvent) { - val project: Project? = event.getData(CommonDataKeys.PROJECT) - val revision: VcsRevisionNumber? = event.getData(VcsDataKeys.VCS_REVISION_NUMBER) - val filePaths = event.getData(VcsDataKeys.CHANGES) ?: return - - if (project == null || revision == null) { - Messages.showErrorDialog(project, "No commit selected.", "Error") - return - } - - val changes = filePaths.mapNotNull { it as? Change } - val patches = changes.mapNotNull { change -> - val changeListManager = ChangeListManager.getInstance(project) - changeListManager.getChangeList(change)?.changes?.firstOrNull()?.beforeRevision?.content - } - - val patchText = patches.joinToString(separator = "\n\n", prefix = "Patch for Revision: $revision\n\n") - Messages.showInfoMessage(project, patchText, "Git Commit Patch") - } - - override fun update(event: AnActionEvent) { - // Enable action only if a project is open and a revision is selected - val project: Project? = event.getData(CommonDataKeys.PROJECT) - val revision: VcsRevisionNumber? = event.getData(VcsDataKeys.VCS_REVISION_NUMBER) - event.presentation.isEnabledAndVisible = project != null && revision != null - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/AppendTextWithChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/AppendTextWithChatAction.kt new file mode 100644 index 00000000..b127cbf3 --- /dev/null +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/AppendTextWithChatAction.kt @@ -0,0 +1,35 @@ +package com.github.simiacryptus.aicoder.actions.legacy + +import com.github.simiacryptus.aicoder.actions.SelectionAction +import com.github.simiacryptus.aicoder.config.AppSettingsState +import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.project.Project +import com.simiacryptus.jopenai.ApiModel.* +import com.simiacryptus.jopenai.util.ClientUtil.toContentList + +class AppendTextWithChatAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun getConfig(project: Project?): String { + return "" + } + + override fun processSelection(state: SelectionState, config: String?): String { + val settings = AppSettingsState.instance + val request = ChatRequest( + model = settings.smartModel.chatModel().modelName, + temperature = settings.temperature + ).copy( + temperature = settings.temperature, + messages = listOf( + ChatMessage(Role.system, "Append text to the end of the user's prompt".toContentList(), null), + ChatMessage(Role.user, state.selectedText.toString().toContentList(), null) + ), + ) + val chatResponse = api.chat(request, settings.smartModel.chatModel()) + val b4 = state.selectedText ?: "" + val str = chatResponse.choices[0].message?.content ?: "" + return b4 + if (str.startsWith(b4)) str.substring(b4.length) else str + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CommentsAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/CommentsAction.kt similarity index 76% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CommentsAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/CommentsAction.kt index a9113fe2..d0328602 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CommentsAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/CommentsAction.kt @@ -1,13 +1,15 @@ -package com.github.simiacryptus.aicoder.actions.code +package com.github.simiacryptus.aicoder.actions.legacy import com.github.simiacryptus.aicoder.actions.SelectionAction import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.ComputerLanguage +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy class CommentsAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT override fun getConfig(project: Project?): String { return "" @@ -19,11 +21,11 @@ class CommentsAction : SelectionAction() { override fun processSelection(state: SelectionState, config: String?): String { return ChatProxy( - clazz = CommentsAction_VirtualAPI::class.java, - api = api, - temperature = AppSettingsState.instance.temperature, - model = AppSettingsState.instance.smartModel.chatModel(), - deserializerRetries = 5 + clazz = CommentsAction_VirtualAPI::class.java, + api = api, + temperature = AppSettingsState.instance.temperature, + model = AppSettingsState.instance.smartModel.chatModel(), + deserializerRetries = 5 ).create().editCode( state.selectedText ?: "", "Add comments to each line explaining the code", diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DocAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/DocAction.kt similarity index 87% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DocAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/DocAction.kt index f8b3ae30..00605af7 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DocAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/DocAction.kt @@ -1,4 +1,4 @@ -package com.github.simiacryptus.aicoder.actions.code +package com.github.simiacryptus.aicoder.actions.legacy import com.github.simiacryptus.aicoder.actions.SelectionAction import com.github.simiacryptus.aicoder.config.AppSettingsState @@ -6,10 +6,12 @@ import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatMod import com.github.simiacryptus.aicoder.util.ComputerLanguage import com.github.simiacryptus.aicoder.util.IndentedText import com.github.simiacryptus.aicoder.util.psi.PsiUtil +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy class DocAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT interface DocAction_VirtualAPI { fun processCode( @@ -27,11 +29,11 @@ class DocAction : SelectionAction() { private val proxy: DocAction_VirtualAPI by lazy { val chatProxy = ChatProxy( - clazz = DocAction_VirtualAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 + clazz = DocAction_VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 ) chatProxy.addExample( DocAction_VirtualAPI.DocAction_ConvertedText().apply { diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/ImplementStubAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ImplementStubAction.kt similarity index 83% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/ImplementStubAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ImplementStubAction.kt index 6278086e..7e5c5471 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/ImplementStubAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ImplementStubAction.kt @@ -1,16 +1,18 @@ -package com.github.simiacryptus.aicoder.actions.code +package com.github.simiacryptus.aicoder.actions.legacy import com.github.simiacryptus.aicoder.actions.SelectionAction import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.ComputerLanguage import com.github.simiacryptus.aicoder.util.psi.PsiUtil +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy import com.simiacryptus.jopenai.util.StringUtil import java.util.* class ImplementStubAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT interface VirtualAPI { fun editCode( @@ -28,11 +30,11 @@ class ImplementStubAction : SelectionAction() { private fun getProxy(): VirtualAPI { return ChatProxy( - clazz = VirtualAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 + clazz = VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 ).create() } @@ -64,7 +66,8 @@ class ImplementStubAction : SelectionAction() { ) } var smallestIntersectingMethod = "" - if (codeContext.isNotEmpty()) smallestIntersectingMethod = codeContext.minByOrNull { it.length() }?.subString(state.entireDocument ?: "") ?: "" + if (codeContext.isNotEmpty()) smallestIntersectingMethod = + codeContext.minByOrNull { it.length() }?.subString(state.entireDocument ?: "") ?: "" var declaration = code declaration = StringUtil.stripSuffix(declaration.trim(), smallestIntersectingMethod) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/InsertImplementationAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/InsertImplementationAction.kt similarity index 90% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/InsertImplementationAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/InsertImplementationAction.kt index ea99154c..19c9923d 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/InsertImplementationAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/InsertImplementationAction.kt @@ -1,4 +1,4 @@ -package com.github.simiacryptus.aicoder.actions.code +package com.github.simiacryptus.aicoder.actions.legacy import com.github.simiacryptus.aicoder.actions.SelectionAction import com.github.simiacryptus.aicoder.config.AppSettingsState @@ -8,11 +8,13 @@ import com.github.simiacryptus.aicoder.util.TextBlock import com.github.simiacryptus.aicoder.util.UITools import com.github.simiacryptus.aicoder.util.psi.PsiClassContext import com.github.simiacryptus.aicoder.util.psi.PsiUtil +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.application.runReadAction import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy class InsertImplementationAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT interface VirtualAPI { fun implementCode( @@ -30,11 +32,11 @@ class InsertImplementationAction : SelectionAction() { private fun getProxy(): VirtualAPI { return ChatProxy( - clazz = VirtualAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 + clazz = VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 ).create() } @@ -123,6 +125,6 @@ class InsertImplementationAction : SelectionAction() { private class PsiClassContextActionParams( val selectionStart: Int, val selectionEnd: Int, - val largestIntersectingComment: SelectionAction.ContextRange? + val largestIntersectingComment: ContextRange? ) } \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RenameVariablesAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/RenameVariablesAction.kt similarity index 82% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RenameVariablesAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/RenameVariablesAction.kt index 69cf001f..add28e25 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RenameVariablesAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/RenameVariablesAction.kt @@ -1,15 +1,17 @@ -package com.github.simiacryptus.aicoder.actions.code +package com.github.simiacryptus.aicoder.actions.legacy import com.github.simiacryptus.aicoder.actions.SelectionAction import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.ComputerLanguage import com.github.simiacryptus.aicoder.util.UITools +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy open class RenameVariablesAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT interface RenameAPI { fun suggestRenames( @@ -28,15 +30,16 @@ open class RenameVariablesAction : SelectionAction() { } } - val proxy: RenameAPI get() { - return ChatProxy( - clazz = RenameAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ).create() - } + val proxy: RenameAPI + get() { + return ChatProxy( + clazz = RenameAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ).create() + } override fun getConfig(project: Project?): String { return "" diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/ReplaceOptionsAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ReplaceWithSuggestionsAction.kt similarity index 74% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/ReplaceOptionsAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ReplaceWithSuggestionsAction.kt index 41f13b2d..d0206b7f 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/ReplaceOptionsAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ReplaceWithSuggestionsAction.kt @@ -1,9 +1,10 @@ -package com.github.simiacryptus.aicoder.actions.generic +package com.github.simiacryptus.aicoder.actions.legacy import com.github.simiacryptus.aicoder.actions.SelectionAction import com.github.simiacryptus.aicoder.config.AppSettingsState import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel import com.github.simiacryptus.aicoder.util.UITools +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy @@ -12,7 +13,9 @@ import kotlin.math.ceil import kotlin.math.ln import kotlin.math.pow -open class ReplaceOptionsAction : SelectionAction() { +open class ReplaceWithSuggestionsAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + interface VirtualAPI { fun suggestText(template: String, examples: List): Suggestions @@ -21,15 +24,16 @@ open class ReplaceOptionsAction : SelectionAction() { } } - val proxy: VirtualAPI get() { - return ChatProxy( - clazz = VirtualAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ).create() - } + val proxy: VirtualAPI + get() { + return ChatProxy( + clazz = VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ).create() + } override fun getConfig(project: Project?): String { return "" @@ -54,6 +58,7 @@ open class ReplaceOptionsAction : SelectionAction() { } open fun choose(choices: List): String { - return UITools.showRadioButtonDialog("Select an option to fill in the blank:", *choices.toTypedArray())?.toString() ?: "" + return UITools.showRadioButtonDialog("Select an option to fill in the blank:", *choices.toTypedArray()) + ?.toString() ?: "" } } \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DictationAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/VoiceToTextAction.kt similarity index 91% rename from src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DictationAction.kt rename to src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/VoiceToTextAction.kt index fe068ddf..d932e8a0 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DictationAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/VoiceToTextAction.kt @@ -1,7 +1,8 @@ -package com.github.simiacryptus.aicoder.actions.generic +package com.github.simiacryptus.aicoder.actions.legacy import com.github.simiacryptus.aicoder.actions.BaseAction import com.github.simiacryptus.aicoder.util.UITools +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.PlatformDataKeys @@ -20,7 +21,9 @@ import javax.sound.sampled.TargetDataLine import javax.swing.JFrame import javax.swing.JLabel -class DictationAction : BaseAction() { +class VoiceToTextAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + override fun handle(e: AnActionEvent) { val continueFn = statusDialog(e)::isVisible @@ -31,7 +34,7 @@ class DictationAction : BaseAction() { AudioRecorder(rawBuffer, 0.05, continueFn).run() log.warn("Recording thread complete") } catch (e: Throwable) { - UITools.error(log,"Error", e) + UITools.error(log, "Error", e) } }, "dication-audio-recorder").start() @@ -41,7 +44,7 @@ class DictationAction : BaseAction() { try { LookbackLoudnessWindowBuffer(rawBuffer, wavBuffer, continueFn).run() } catch (e: Throwable) { - UITools.error(log,"Error", e) + UITools.error(log, "Error", e) } log.warn("Audio processing thread complete") }, "dictation-audio-processor").start() @@ -58,7 +61,7 @@ class DictationAction : BaseAction() { try { dictationPump.run() } catch (e: Throwable) { - UITools.error(log,"Error", e) + UITools.error(log, "Error", e) } log.warn("Speech-To-Text thread complete") }, "dictation-api-processor").start() @@ -121,7 +124,7 @@ class DictationAction : BaseAction() { } companion object { - private val log = LoggerFactory.getLogger(DictationAction::class.java) + private val log = LoggerFactory.getLogger(VoiceToTextAction::class.java) private val pool = Executors.newFixedThreadPool(1) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownImplementActionGroup.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownImplementActionGroup.kt index b5038bf5..729d3538 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownImplementActionGroup.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownImplementActionGroup.kt @@ -6,14 +6,14 @@ import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatMod import com.github.simiacryptus.aicoder.util.ComputerLanguage import com.github.simiacryptus.aicoder.util.UITools import com.intellij.openapi.actionSystem.ActionGroup +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.Project import com.simiacryptus.jopenai.proxy.ChatProxy -import com.simiacryptus.skyenet.core.actors.CodingActor.Companion.indent -import org.apache.commons.text.StringEscapeUtils.escapeHtml4 class MarkdownImplementActionGroup : ActionGroup() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT private val markdownLanguages = listOf( "sql", "java", "asp", "c", "clojure", "coffee", "cpp", "csharp", "css", "bash", "go", "java", "javascript", "less", "make", "matlab", "objectivec", "pascal", "PHP", "Perl", "python", "rust", "scss", "sql", "svg", @@ -41,6 +41,7 @@ class MarkdownImplementActionGroup : ActionGroup() { } open class MarkdownImplementAction(private val language: String) : SelectionAction(true) { + override fun getActionUpdateThread() = ActionUpdateThread.BGT init { templatePresentation.text = language templatePresentation.description = language @@ -57,11 +58,11 @@ class MarkdownImplementActionGroup : ActionGroup() { private fun getProxy(): ConversionAPI { return ChatProxy( - clazz = ConversionAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 + clazz = ConversionAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 ).create() } @@ -75,7 +76,7 @@ class MarkdownImplementActionGroup : ActionGroup() { | | |```$language - |${code?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} + |${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} |``` | |""".trimMargin() diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownListAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownListAction.kt index 712773fe..769b271c 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownListAction.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownListAction.kt @@ -9,6 +9,7 @@ import com.github.simiacryptus.aicoder.util.UITools.getIndent import com.github.simiacryptus.aicoder.util.UITools.insertString import com.github.simiacryptus.aicoder.util.psi.PsiUtil.getAll import com.github.simiacryptus.aicoder.util.psi.PsiUtil.getSmallestIntersecting +import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.application.ApplicationManager @@ -16,6 +17,7 @@ import com.simiacryptus.jopenai.proxy.ChatProxy import com.simiacryptus.jopenai.util.StringUtil class MarkdownListAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT interface ListAPI { fun newListItems( @@ -31,10 +33,10 @@ class MarkdownListAction : BaseAction() { val proxy: ListAPI get() { val chatProxy = ChatProxy( - clazz = ListAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - deserializerRetries = 5, + clazz = ListAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + deserializerRetries = 5, ) chatProxy.addExample( returnValue = ListAPI.Items( diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsComponent.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsComponent.kt index 1bda5f07..54803e80 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsComponent.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsComponent.kt @@ -74,8 +74,8 @@ class AppSettingsComponent : com.intellij.openapi.Disposable { val openFileDescriptor = OpenFileDescriptor(project, virtualFile!!, virtualFile.length.toInt()) FileEditorManager.getInstance(project!!) .openTextEditor(openFileDescriptor, true)?.document?.setReadOnly( - true - ) + true + ) } } } @@ -134,7 +134,7 @@ class AppSettingsComponent : com.intellij.openapi.Disposable { columnModel.getColumn(1).preferredWidth = 200 columnModel.getColumn(2).preferredWidth = 200 val keyColumnIndex = 1 - getColumnModel().getColumn(keyColumnIndex).cellRenderer = object : DefaultTableCellRenderer() { + columnModel.getColumn(keyColumnIndex).cellRenderer = object : DefaultTableCellRenderer() { override fun setValue(value: Any?) { text = if (value is String && value.isNotEmpty()) value.map { '*' }.joinToString("") else value?.toString() @@ -161,8 +161,7 @@ class AppSettingsComponent : com.intellij.openapi.Disposable { this.fastModel.isEditable = true } - companion object { - } + companion object; override fun dispose() { } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsConfigurable.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsConfigurable.kt index 6cea19db..33c52a96 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsConfigurable.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsConfigurable.kt @@ -3,17 +3,17 @@ package com.github.simiacryptus.aicoder.config import com.github.simiacryptus.aicoder.util.UITools open class AppSettingsConfigurable : UIAdapter(AppSettingsState.instance) { - override fun read(component: AppSettingsComponent, settings: AppSettingsState) { - UITools.readKotlinUIViaReflection(component, settings) - } + override fun read(component: AppSettingsComponent, settings: AppSettingsState) { + UITools.readKotlinUIViaReflection(component, settings) + } - override fun write(settings: AppSettingsState, component: AppSettingsComponent) { - UITools.writeKotlinUIViaReflection(settings, component) - } + override fun write(settings: AppSettingsState, component: AppSettingsComponent) { + UITools.writeKotlinUIViaReflection(settings, component) + } - override fun getPreferredFocusedComponent() = component?.temperature + override fun getPreferredFocusedComponent() = component?.temperature - override fun newComponent() = AppSettingsComponent() + override fun newComponent() = AppSettingsComponent() - override fun newSettings() = AppSettingsState() + override fun newSettings() = AppSettingsState() } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsState.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsState.kt index 634f7a0f..244626bd 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsState.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsState.kt @@ -6,7 +6,6 @@ import com.intellij.openapi.components.PersistentStateComponent import com.intellij.openapi.components.State import com.intellij.openapi.components.Storage import com.intellij.util.xmlb.XmlSerializerUtil -import com.jetbrains.rd.util.firstOrNull import com.simiacryptus.jopenai.models.ChatModels import com.simiacryptus.jopenai.util.JsonUtil import java.io.File @@ -65,7 +64,7 @@ data class AppSettingsState( AppSettingsState() } XmlSerializerUtil.copyBean(fromJson, this) - recentCommands.clear(); + recentCommands.clear() recentCommands.putAll(fromJson.recentCommands) // editorActions.actionSettings.clear(); // editorActions.actionSettings.putAll(fromJson.editorActions.actionSettings) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/MRUItems.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/MRUItems.kt index eb7b134a..37483e9f 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/MRUItems.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/config/MRUItems.kt @@ -9,7 +9,7 @@ class MRUItems { private var historyLimit = 10 fun addInstructionToHistory(instruction: CharSequence) { synchronized(mostRecentHistory) { - if(mostRecentHistory.contains(instruction.toString())) { + if (mostRecentHistory.contains(instruction.toString())) { mostRecentHistory.remove(instruction.toString()) } mostRecentHistory.add(instruction.toString()) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt index 80340c7e..c5b3e177 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt @@ -125,7 +125,7 @@ class StaticAppSettingsConfigurable : AppSettingsConfigurable() { component.temperature.text = settings.temperature.toString() component.pluginHome.text = settings.pluginHome.absolutePath val model = component.apis.model as DefaultTableModel - model.setRowCount(0) // Clear existing rows + model.rowCount = 0 // Clear existing rows APIProvider.values().forEach { value -> val key = value.name model.addRow(arrayOf(key, settings.apiKey?.get(key) ?: "", settings.apiBase?.get(key) ?: value.base)) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/UIAdapter.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/UIAdapter.kt index b594acbf..be80365f 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/UIAdapter.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/config/UIAdapter.kt @@ -6,72 +6,72 @@ import com.intellij.openapi.options.Configurable import javax.swing.JComponent abstract class UIAdapter( - protected val settingsInstance: S, - protected var component: C? = null, + protected val settingsInstance: S, + protected var component: C? = null, ) : Configurable { - @Volatile - private var mainPanel: JComponent? = null - override fun getDisplayName(): String { - return "AICoder Settings" - } + @Volatile + private var mainPanel: JComponent? = null + override fun getDisplayName(): String { + return "AICoder Settings" + } - override fun getPreferredFocusedComponent(): JComponent? = null + override fun getPreferredFocusedComponent(): JComponent? = null - override fun createComponent(): JComponent? { - if (null == mainPanel) { - synchronized(this) { + override fun createComponent(): JComponent? { if (null == mainPanel) { - val component = newComponent() - this.component = component - mainPanel = build(component) - write(settingsInstance, component) + synchronized(this) { + if (null == mainPanel) { + val component = newComponent() + this.component = component + mainPanel = build(component) + write(settingsInstance, component) + } + } } - } + return mainPanel } - return mainPanel - } - abstract fun newComponent(): C - abstract fun newSettings(): S - private fun getSettings(component : C? = this.component) = when (component) { - null -> settingsInstance - else -> { - val buffer = newSettings() - read(component, buffer) - buffer + abstract fun newComponent(): C + abstract fun newSettings(): S + private fun getSettings(component: C? = this.component) = when (component) { + null -> settingsInstance + else -> { + val buffer = newSettings() + read(component, buffer) + buffer + } } - } - override fun isModified() = when { - component == null -> false - getSettings() != settingsInstance -> true - else -> false - } + override fun isModified() = when { + component == null -> false + getSettings() != settingsInstance -> true + else -> false + } - override fun apply() { - if (component != null) read(component!!, settingsInstance) - } + override fun apply() { + if (component != null) read(component!!, settingsInstance) + } - override fun reset() { - if (component != null) write(settingsInstance, component!!) - } + override fun reset() { + if (component != null) write(settingsInstance, component!!) + } - override fun disposeUIResources() { - val component = component - this.component = null - if(component != null && component is Disposable) component.dispose() - } + override fun disposeUIResources() { + val component = component + this.component = null + if (component != null && component is Disposable) component.dispose() + } - open fun build(component: C): JComponent = - UITools.buildFormViaReflection(component, false)!! + open fun build(component: C): JComponent = + UITools.buildFormViaReflection(component, false)!! - open fun read(component: C, settings: S) { - UITools.readKotlinUIViaReflection(component, settings) - } + open fun read(component: C, settings: S) { + UITools.readKotlinUIViaReflection(component, settings) + } - open fun write(settings: S, component: C) { - UITools.writeKotlinUIViaReflection(settings, component) - } + open fun write(settings: S, component: C) { + UITools.writeKotlinUIViaReflection(settings, component) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/UsageTable.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/UsageTable.kt index d34e04f6..8cd24676 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/UsageTable.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/config/UsageTable.kt @@ -15,107 +15,106 @@ import javax.swing.table.AbstractTableModel import javax.swing.table.DefaultTableCellRenderer class UsageTable( - val usage: UsageInterface + val usage: UsageInterface ) : JPanel(BorderLayout()) { - private val buttonPanel = JPanel() - val columnNames = arrayOf("Model", "Prompt", "Completion", "Cost") - - val rowData by lazy { - usage.getUserUsageSummary(IdeaOpenAIClient.localUser).map { entry -> - listOf( - entry.key.modelName, - entry.value.prompt_tokens.toString(), - entry.value.completion_tokens.toString(), - String.format("%.2f", entry.value.cost) - ).toMutableList() - }.toMutableList() - } - - private val dataModel by lazy { - object : AbstractTableModel() { - override fun getColumnName(column: Int): String { - return columnNames.get(column).toString() - } - - override fun getRowCount(): Int { - return rowData.size - } - - override fun getColumnCount(): Int { - return columnNames.size - } - - override fun getValueAt(row: Int, col: Int): Any { - return rowData[row][col] - } - - override fun isCellEditable(row: Int, column: Int): Boolean { - return true - } - - override fun setValueAt(value: Any, row: Int, col: Int) { - rowData[row][col] = value.toString() - fireTableCellUpdated(row, col) - } + private val buttonPanel = JPanel() + val columnNames = arrayOf("Model", "Prompt", "Completion", "Cost") + + val rowData by lazy { + usage.getUserUsageSummary(IdeaOpenAIClient.localUser).map { entry -> + listOf( + entry.key.modelName, + entry.value.prompt_tokens.toString(), + entry.value.completion_tokens.toString(), + String.format("%.2f", entry.value.cost) + ).toMutableList() + }.toMutableList() + } + + private val dataModel by lazy { + object : AbstractTableModel() { + override fun getColumnName(column: Int): String { + return columnNames.get(column).toString() + } + + override fun getRowCount(): Int { + return rowData.size + } + + override fun getColumnCount(): Int { + return columnNames.size + } + + override fun getValueAt(row: Int, col: Int): Any { + return rowData[row][col] + } + override fun isCellEditable(row: Int, column: Int): Boolean { + return true + } + + override fun setValueAt(value: Any, row: Int, col: Int) { + rowData[row][col] = value.toString() + fireTableCellUpdated(row, col) + } + + } } - } - private val jtable by lazy { JBTable(dataModel) } + private val jtable by lazy { JBTable(dataModel) } - private val scrollpane by lazy { JBScrollPane(jtable) } + private val scrollpane by lazy { JBScrollPane(jtable) } - private val clearButton by lazy { - JButton(object : AbstractAction("Clear") { - override fun actionPerformed(e: ActionEvent?) { - rowData.clear() - usage.clear() - this@UsageTable.parent.invalidate() - } - }) - } + private val clearButton by lazy { + JButton(object : AbstractAction("Clear") { + override fun actionPerformed(e: ActionEvent?) { + rowData.clear() + usage.clear() + this@UsageTable.parent.invalidate() + } + }) + } - init { - jtable.columnModel.getColumn(0).cellRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(1).cellRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(2).cellRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(3).cellRenderer = DefaultTableCellRenderer() + init { + jtable.columnModel.getColumn(0).cellRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(1).cellRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(2).cellRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(3).cellRenderer = DefaultTableCellRenderer() + + val editor = object : JXTable.GenericEditor() { + override fun isCellEditable(anEvent: EventObject?) = false + } + jtable.columnModel.getColumn(0).cellEditor = editor + jtable.columnModel.getColumn(1).cellEditor = editor + jtable.columnModel.getColumn(2).cellEditor = editor + jtable.columnModel.getColumn(3).cellEditor = editor + + jtable.columnModel.getColumn(0).headerRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(1).headerRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(2).headerRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(3).headerRenderer = DefaultTableCellRenderer() + + // Set the preferred width for the first column (checkboxes) to the header label width + initCol(0) + initCol(1) + initCol(2) + initCol(3) + + jtable.tableHeader.defaultRenderer = DefaultTableCellRenderer() + + add(scrollpane, BorderLayout.CENTER) + buttonPanel.add(clearButton) + add(buttonPanel, BorderLayout.SOUTH) + } - val editor = object : JXTable.GenericEditor() { - override fun isCellEditable(anEvent: EventObject?) = false + private fun initCol(idx: Int) { + val headerRenderer = jtable.tableHeader.defaultRenderer + val headerValue = jtable.columnModel.getColumn(idx).headerValue + val headerComp = headerRenderer.getTableCellRendererComponent(jtable, headerValue, false, false, 0, idx) + jtable.columnModel.getColumn(idx).preferredWidth = headerComp.preferredSize.width } - jtable.columnModel.getColumn(0).cellEditor = editor - jtable.columnModel.getColumn(1).cellEditor = editor - jtable.columnModel.getColumn(2).cellEditor = editor - jtable.columnModel.getColumn(3).cellEditor = editor - - jtable.columnModel.getColumn(0).headerRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(1).headerRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(2).headerRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(3).headerRenderer = DefaultTableCellRenderer() - - // Set the preferred width for the first column (checkboxes) to the header label width - initCol(0) - initCol(1) - initCol(2) - initCol(3) - - jtable.tableHeader.defaultRenderer = DefaultTableCellRenderer() - - add(scrollpane, BorderLayout.CENTER) - buttonPanel.add(clearButton) - add(buttonPanel, BorderLayout.SOUTH) - } - - private fun initCol(idx: Int) { - val headerRenderer = jtable.tableHeader.defaultRenderer - val headerValue = jtable.columnModel.getColumn(idx).headerValue - val headerComp = headerRenderer.getTableCellRendererComponent(jtable, headerValue, false, false, 0, idx) - jtable.columnModel.getColumn(idx).preferredWidth = headerComp.preferredSize.width - } - - companion object { - } + + companion object } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/ui/ConsolidatedWidgetFactory.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/ui/ConsolidatedWidgetFactory.kt new file mode 100644 index 00000000..e8880897 --- /dev/null +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/ui/ConsolidatedWidgetFactory.kt @@ -0,0 +1,145 @@ +package com.github.simiacryptus.aicoder.ui + +import com.github.simiacryptus.aicoder.config.AppSettingsState +import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.chatModel +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.popup.JBPopup +import com.intellij.openapi.ui.popup.JBPopupFactory +import com.intellij.openapi.wm.StatusBar +import com.intellij.openapi.wm.StatusBarWidget +import com.intellij.openapi.wm.StatusBarWidgetFactory +import com.intellij.ui.CollectionListModel +import com.intellij.ui.SimpleListCellRenderer +import com.intellij.ui.components.JBList +import com.simiacryptus.jopenai.models.ChatModels +import kotlinx.coroutines.CoroutineScope +import java.awt.BorderLayout +import javax.swing.* + +class ConsolidatedWidgetFactory : StatusBarWidgetFactory { + + class ConsolidatedWidget : StatusBarWidget, StatusBarWidget.MultipleTextValuesPresentation { + + private var statusBar: StatusBar? = null + private var activeModel: String = AppSettingsState.instance.smartModel.chatModel().modelName + var models: List = models() + private val temperatureSlider by lazy { + val slider = JSlider(0, 100, (AppSettingsState.instance.temperature * 100).toInt()) + slider.addChangeListener { AppSettingsState.instance.temperature = slider.value / 100.0 } + slider + } + + init { + AppSettingsState.instance.addOnSettingsLoadedListener { + models = models() + statusBar?.updateWidget(ID()) + } + } + + fun models() = ChatModels.values().filter { + AppSettingsState.instance.apiKey?.filter { it.value.isNotBlank() }?.keys?.contains(it.value.provider.name) + ?: false + }.map { it.value }.toList() + + override fun ID(): String { + return "ConsolidatedComponent" + } + + override fun getPresentation(): StatusBarWidget.WidgetPresentation { + return this + } + + override fun install(statusBar: StatusBar) { + this.statusBar = statusBar + } + + override fun dispose() { + //connection?.disconnect() + } + + override fun getTooltipText(): String { + return "Current active model and temperature control" + } + + override fun getSelectedValue(): String { + return activeModel + } + + private fun getRenderer(): ListCellRenderer = object : SimpleListCellRenderer() { + override fun customize( + list: JList, + value: String?, + index: Int, + selected: Boolean, + hasFocus: Boolean + ) { + text = value // Here you can add more customization if needed + if (value != null) { + val model = models.find { it.modelName == value } + text = "${model?.provider?.name} - $value" + } + } + } + + override fun getPopup(): JBPopup { + val inputField = JTextField() + val listModel = CollectionListModel(models.map { it.modelName }) + val list = JBList(listModel) + list.cellRenderer = getRenderer() + + val panel = JPanel(BorderLayout()) + panel.add(inputField, BorderLayout.NORTH) + panel.add(JScrollPane(list), BorderLayout.CENTER) + panel.add(temperatureSlider, BorderLayout.SOUTH) + + val popup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, inputField) + .setRequestFocus(true) + .setCancelOnClickOutside(true) + .createPopup() + + list.addListSelectionListener { + val selectedValue = list.selectedValue + activeModel = selectedValue + AppSettingsState.instance.smartModel = selectedValue + statusBar?.updateWidget(ID()) + popup.closeOk(null) + } + + inputField.addActionListener { + val inputValue = inputField.text + if (inputValue.isNotEmpty()) { + activeModel = inputValue + AppSettingsState.instance.smartModel = inputValue + statusBar?.updateWidget(ID()) + popup.closeOk(null) + } + } + + return popup + } + } + + override fun getId(): String { + return "ConsolidatedComponent" + } + + override fun getDisplayName(): String { + return "Consolidated Widget" + } + + override fun createWidget(project: Project, scope: CoroutineScope): StatusBarWidget { + return ConsolidatedWidget() + } + + override fun createWidget(project: Project): StatusBarWidget { + return ConsolidatedWidget() + } + + override fun isAvailable(project: Project): Boolean { + return true + } + + override fun canBeEnabledOn(statusBar: StatusBar): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/ui/ModelSelectionWidgetFactory.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/ui/ModelSelectionWidgetFactory.kt index a9cf78ee..b7d39e9e 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/ui/ModelSelectionWidgetFactory.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/ui/ModelSelectionWidgetFactory.kt @@ -18,99 +18,99 @@ import javax.swing.* class ModelSelectionWidgetFactory : StatusBarWidgetFactory { - class ModelSelectionWidget : StatusBarWidget, StatusBarWidget.MultipleTextValuesPresentation { + class ModelSelectionWidget : StatusBarWidget, StatusBarWidget.MultipleTextValuesPresentation { - private var statusBar: StatusBar? = null - private var activeModel: String = AppSettingsState.instance.smartModel.chatModel().modelName - var models: List = models() + private var statusBar: StatusBar? = null + private var activeModel: String = AppSettingsState.instance.smartModel.chatModel().modelName + var models: List = models() - init { - AppSettingsState.instance.addOnSettingsLoadedListener { - models = models() - statusBar?.updateWidget(ID()) + init { + AppSettingsState.instance.addOnSettingsLoadedListener { + models = models() + statusBar?.updateWidget(ID()) + } } - } - fun models() = ChatModels.values().filter { - AppSettingsState.instance.apiKey?.filter { it.value.isNotBlank() }?.keys?.contains(it.value.provider.name) - ?: false - }.map { it.value }.toList() + fun models() = ChatModels.values().filter { + AppSettingsState.instance.apiKey?.filter { it.value.isNotBlank() }?.keys?.contains(it.value.provider.name) + ?: false + }.map { it.value }.toList() - override fun ID(): String { - return "ModelSelectionComponent" - } - - override fun getPresentation(): StatusBarWidget.WidgetPresentation { - return this - } - - override fun install(statusBar: StatusBar) { - this.statusBar = statusBar - } - - override fun dispose() { - //connection?.disconnect() - } - - override fun getTooltipText(): String { - return "Current active model" - } - - override fun getSelectedValue(): String { - return activeModel - } - - private fun getRenderer(): ListCellRenderer = object : SimpleListCellRenderer() { - override fun customize( - list: JList, - value: String?, - index: Int, - selected: Boolean, - hasFocus: Boolean - ) { - text = value // Here you can add more customization if needed - if (value != null) { - val model = models.find { it.modelName == value } - text = "${model?.provider?.name} - $value" - } + override fun ID(): String { + return "ModelSelectionComponent" + } + + override fun getPresentation(): StatusBarWidget.WidgetPresentation { + return this } - } - - override fun getPopup(): JBPopup { - val inputField = JTextField() - val listModel = CollectionListModel(models.map { it.modelName }) - val list = JBList(listModel) - list.cellRenderer = getRenderer() - - val panel = JPanel(BorderLayout()) - panel.add(inputField, BorderLayout.NORTH) - panel.add(JScrollPane(list), BorderLayout.CENTER) - - val popup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, inputField) - .setRequestFocus(true) - .setCancelOnClickOutside(true) - .createPopup() - - list.addListSelectionListener { - val selectedValue = list.selectedValue - activeModel = selectedValue - AppSettingsState.instance.smartModel = selectedValue - statusBar?.updateWidget(ID()) - popup.closeOk(null) + + override fun install(statusBar: StatusBar) { + this.statusBar = statusBar + } + + override fun dispose() { + //connection?.disconnect() } - inputField.addActionListener { - val inputValue = inputField.text - if (inputValue.isNotEmpty()) { - activeModel = inputValue - AppSettingsState.instance.smartModel = inputValue - statusBar?.updateWidget(ID()) - popup.closeOk(null) - } + override fun getTooltipText(): String { + return "Current active model" } - return popup - } + override fun getSelectedValue(): String { + return activeModel + } + + private fun getRenderer(): ListCellRenderer = object : SimpleListCellRenderer() { + override fun customize( + list: JList, + value: String?, + index: Int, + selected: Boolean, + hasFocus: Boolean + ) { + text = value // Here you can add more customization if needed + if (value != null) { + val model = models.find { it.modelName == value } + text = "${model?.provider?.name} - $value" + } + } + } + + override fun getPopup(): JBPopup { + val inputField = JTextField() + val listModel = CollectionListModel(models.map { it.modelName }) + val list = JBList(listModel) + list.cellRenderer = getRenderer() + + val panel = JPanel(BorderLayout()) + panel.add(inputField, BorderLayout.NORTH) + panel.add(JScrollPane(list), BorderLayout.CENTER) + + val popup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, inputField) + .setRequestFocus(true) + .setCancelOnClickOutside(true) + .createPopup() + + list.addListSelectionListener { + val selectedValue = list.selectedValue + activeModel = selectedValue + AppSettingsState.instance.smartModel = selectedValue + statusBar?.updateWidget(ID()) + popup.closeOk(null) + } + + inputField.addActionListener { + val inputValue = inputField.text + if (inputValue.isNotEmpty()) { + activeModel = inputValue + AppSettingsState.instance.smartModel = inputValue + statusBar?.updateWidget(ID()) + popup.closeOk(null) + } + } + + return popup + } } override fun getId(): String { diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/ui/TemperatureControlWidgetFactory.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/ui/TemperatureControlWidgetFactory.kt index 6f183572..2f14c424 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/ui/TemperatureControlWidgetFactory.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/ui/TemperatureControlWidgetFactory.kt @@ -1,5 +1,6 @@ package com.github.simiacryptus.aicoder.ui +import icons.MyIcons import com.github.simiacryptus.aicoder.config.AppSettingsState import com.intellij.openapi.project.Project import com.intellij.openapi.ui.popup.JBPopupFactory @@ -9,7 +10,6 @@ import com.intellij.openapi.wm.StatusBarWidget import com.intellij.openapi.wm.StatusBarWidgetFactory import com.intellij.ui.awt.RelativePoint import com.intellij.ui.components.JBLabel -import com.intellij.ui.components.Panel import com.intellij.ui.components.panels.VerticalLayout import com.intellij.util.Consumer import kotlinx.coroutines.CoroutineScope @@ -19,7 +19,6 @@ import java.awt.Point import java.awt.event.MouseAdapter import java.awt.event.MouseEvent import java.net.URI -import java.util.concurrent.Executors import javax.swing.Icon import javax.swing.JPanel import javax.swing.JSlider @@ -29,9 +28,7 @@ import javax.swing.event.ChangeListener class TemperatureControlWidgetFactory : StatusBarWidgetFactory { - companion object { - val pool = Executors.newCachedThreadPool() - } + companion object class TemperatureControlWidget : StatusBarWidget, StatusBarWidget.IconPresentation { @@ -116,14 +113,14 @@ class TemperatureControlWidgetFactory : StatusBarWidgetFactory { } override fun getIcon(): Icon? = - IconLoader.findIcon( - url = javaClass.classLoader.getResource("./META-INF/toolbarIcon.svg"), - storeToCache = true - ) + MyIcons.icon override fun getPresentation(): StatusBarWidget.WidgetPresentation { return this } + + companion object { + } } override fun getId(): String { diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/CheckboxTaskManager.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/CheckboxTaskManager.kt deleted file mode 100644 index fb7905bc..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/CheckboxTaskManager.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import javax.swing.JCheckBox -import javax.swing.JPanel - -/** - * Manages tasks represented as checkboxes within a UI component. - */ -class CheckboxTaskManager { - private val taskCheckboxes: MutableMap = mutableMapOf() - - /** - * Adds a task with a unique identifier. - */ - fun addTask(taskId: String, taskLabel: String) { - val checkBox = JCheckBox(taskLabel) - taskCheckboxes[taskId] = checkBox - // Additional setup for the checkbox can be added here - } - - /** - * Removes a task by its unique identifier. - */ - fun removeTask(taskId: String) { - taskCheckboxes.remove(taskId) - // Additional cleanup for the task can be added here - } - - /** - * Updates the UI component to display the current tasks. - * @param panel The JPanel to which the checkboxes should be added. - */ - fun updateUI(panel: JPanel) { - panel.removeAll() - taskCheckboxes.values.forEach { checkBox -> - panel.add(checkBox) - } - panel.revalidate() - panel.repaint() - } - - /** - * Retrieves the state of a specific task. - * @return Boolean indicating whether the task is checked or not. - */ - fun isTaskChecked(taskId: String): Boolean { - return taskCheckboxes[taskId]?.isSelected ?: false - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeChatSocketManager.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeChatSocketManager.kt index a39c8be0..9058bef4 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeChatSocketManager.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeChatSocketManager.kt @@ -2,48 +2,46 @@ package com.github.simiacryptus.aicoder.util import com.simiacryptus.jopenai.OpenAIClient import com.simiacryptus.jopenai.models.ChatModels -import com.simiacryptus.skyenet.core.actors.CodingActor.Companion.indent import com.simiacryptus.skyenet.core.platform.Session import com.simiacryptus.skyenet.core.platform.StorageInterface import com.simiacryptus.skyenet.core.platform.User import com.simiacryptus.skyenet.webui.application.ApplicationServer import com.simiacryptus.skyenet.webui.chat.ChatSocketManager -import org.apache.commons.text.StringEscapeUtils open class CodeChatSocketManager( - session: Session, - val language: String, - val filename: String, - val codeSelection: String, - api: OpenAIClient, - model: ChatModels, - storage: StorageInterface?, + session: Session, + val language: String, + val filename: String, + val codeSelection: String, + api: OpenAIClient, + model: ChatModels, + storage: StorageInterface?, ) : ChatSocketManager( - session = session, - model = model, - userInterfacePrompt = """ + session = session, + model = model, + userInterfacePrompt = """ |# `$filename` | |```$language |${/*StringEscapeUtils.escapeHtml4*/(codeSelection)/*.indent(" ")*/} |``` """.trimMargin().trim(), - systemPrompt = """ + systemPrompt = """ |You are a helpful AI that helps people with coding. | |You will be answering questions about the following code located in `$filename`: | |```$language |${ - codeSelection/*.indent(" ")*/ - }} + codeSelection/*.indent(" ")*/ + }} |``` | |Responses may use markdown formatting, including code blocks. """.trimMargin(), - api = api, - applicationClass = ApplicationServer::class.java, - storage = storage, + api = api, + applicationClass = ApplicationServer::class.java, + storage = storage, ) { - override fun canWrite(user: User?): Boolean = true + override fun canWrite(user: User?): Boolean = true } \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/ComputerLanguage.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/ComputerLanguage.kt index ba934bfb..5e128cdc 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/ComputerLanguage.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/util/ComputerLanguage.kt @@ -64,6 +64,14 @@ enum class ComputerLanguage(configuration: Configuration) { .setLineComments(LineComment.Factory("#")) .setFileExtensions("txt") ), + XML( + Configuration() + .setDocumentationStyle("XML") + .setLineComments(BlockComment.Factory("")) + .setBlockComments(BlockComment.Factory("")) + .setDocComments(BlockComment.Factory("")) + .setFileExtensions("xml") + ), Ada( Configuration() .setLineComments(LineComment.Factory("--")) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaOpenAIClient.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaOpenAIClient.kt index 140b4cb3..1e3c63d5 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaOpenAIClient.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaOpenAIClient.kt @@ -26,225 +26,225 @@ import javax.swing.JPanel import javax.swing.JTextArea class IdeaOpenAIClient : OpenAIClient( - key = AppSettingsState.instance.apiKey?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() - ?.associate { it.key to it.value } ?: mapOf(), - apiBase = AppSettingsState.instance.apiBase?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() - ?.associate { it.key to it.value } ?: mapOf(), + key = AppSettingsState.instance.apiKey?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() + ?.associate { it.key to it.value } ?: mapOf(), + apiBase = AppSettingsState.instance.apiBase?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() + ?.associate { it.key to it.value } ?: mapOf(), ) { - init { - log.info("Initializing OpenAI Client", Throwable()) - require(key.size == apiBase.size) { - "API Key not configured for all providers: ${key.keys} != ${APIProvider.values().toList()}" + init { + log.info("Initializing OpenAI Client", Throwable()) + require(key.size == apiBase.size) { + "API Key not configured for all providers: ${key.keys} != ${APIProvider.values().toList()}" + } } - } - private val isInRequest = AtomicBoolean(false) + private val isInRequest = AtomicBoolean(false) - override fun onUsage(model: OpenAIModel?, tokens: Usage) { + override fun onUsage(model: OpenAIModel?, tokens: Usage) { // AppSettingsState.instance.tokenCounter += tokens.total_tokens - ApplicationServices.usageManager.incrementUsage(currentSession, localUser, model!!, tokens) - } - - override fun authorize(request: HttpRequest, apiProvider: APIProvider) { - val checkApiKey = UITools.checkApiKey(key.get(apiProvider)!!) - key = key.toMutableMap().let { - it[apiProvider] = checkApiKey - it - }.entries.toTypedArray().associate { it.key to it.value } - super.authorize(request, apiProvider) - } - - @Suppress("NAME_SHADOWING") - override fun chat( - chatRequest: ChatRequest, - model: ChatModels - ): ChatResponse { - lastEvent ?: return super.chat(chatRequest, model) - if (isInRequest.getAndSet(true)) { - val response = super.chat(chatRequest, model) - if(null != response.usage) { - UITools.logAction( - """ + ApplicationServices.usageManager.incrementUsage(currentSession, localUser, model!!, tokens) + } + + override fun authorize(request: HttpRequest, apiProvider: APIProvider) { + val checkApiKey = UITools.checkApiKey(key.get(apiProvider)!!) + key = key.toMutableMap().let { + it[apiProvider] = checkApiKey + it + }.entries.toTypedArray().associate { it.key to it.value } + super.authorize(request, apiProvider) + } + + @Suppress("NAME_SHADOWING") + override fun chat( + chatRequest: ChatRequest, + model: ChatModels + ): ChatResponse { + lastEvent ?: return super.chat(chatRequest, model) + if (isInRequest.getAndSet(true)) { + val response = super.chat(chatRequest, model) + if (null != response.usage) { + UITools.logAction( + """ |Chat Response: ${JsonUtil.toJson(response.usage!!)} """.trimMargin().trim() - ) - } - return response - } else { - try { - if (!AppSettingsState.instance.editRequests) { - val response = super.chat(chatRequest, model) - if(null != response.usage) { - UITools.logAction( - """ + ) + } + return response + } else { + try { + if (!AppSettingsState.instance.editRequests) { + val response = super.chat(chatRequest, model) + if (null != response.usage) { + UITools.logAction( + """ |Chat Response: ${JsonUtil.toJson(response.usage!!)} """.trimMargin().trim() - ) - } - return response - } - return withJsonDialog(chatRequest, { chatRequest -> - UITools.run( - lastEvent!!.project, "OpenAI Request", true, suppressProgress = false - ) { - val response = super.chat(chatRequest, model) - if(null != response.usage) { - UITools.logAction( - """ + ) + } + return response + } + return withJsonDialog(chatRequest, { chatRequest -> + UITools.run( + lastEvent!!.project, "OpenAI Request", true, suppressProgress = false + ) { + val response = super.chat(chatRequest, model) + if (null != response.usage) { + UITools.logAction( + """ |Chat Response: ${JsonUtil.toJson(response.usage!!)} """.trimMargin().trim() - ) + ) + } + response + } + }, "Edit Chat Request") + } finally { + isInRequest.set(false) } - response - } - }, "Edit Chat Request") - } finally { - isInRequest.set(false) - } + } } - } - override fun complete(request: CompletionRequest, model: OpenAITextModel): CompletionResponse { - lastEvent ?: return super.complete(request, model) - if (isInRequest.getAndSet(true)) { - val response = super.complete(request, model) - UITools.logAction( - """ + override fun complete(request: CompletionRequest, model: OpenAITextModel): CompletionResponse { + lastEvent ?: return super.complete(request, model) + if (isInRequest.getAndSet(true)) { + val response = super.complete(request, model) + UITools.logAction( + """ |Completion Response: ${JsonUtil.toJson(response.usage!!)} """.trimMargin().trim() - ) - return response - } else { - try { - if (!AppSettingsState.instance.editRequests) return super.complete(request, model) - return withJsonDialog(request, { - val completionRequest = it - UITools.run( - lastEvent!!.project, "OpenAI Request", true, suppressProgress = false - ) { - val response = super.complete(completionRequest, model) - UITools.logAction( - """ + ) + return response + } else { + try { + if (!AppSettingsState.instance.editRequests) return super.complete(request, model) + return withJsonDialog(request, { + val completionRequest = it + UITools.run( + lastEvent!!.project, "OpenAI Request", true, suppressProgress = false + ) { + val response = super.complete(completionRequest, model) + UITools.logAction( + """ |Completion Response: ${JsonUtil.toJson(response.usage!!)} """.trimMargin().trim() - ) - response - } - }, "Edit Completion Request") - } finally { - isInRequest.set(false) - } - } - } - - override fun edit(editRequest: EditRequest): CompletionResponse { - lastEvent ?: return super.edit(editRequest) - if (isInRequest.getAndSet(true)) { - return super.edit(editRequest) - } else { - try { - if (!AppSettingsState.instance.editRequests) return super.edit(editRequest) - return withJsonDialog(editRequest, { request -> - UITools.run( - lastEvent!!.project, "OpenAI Request", true, suppressProgress = false - ) { - super.edit(request) - } - }, "Edit Edit Request") - } finally { - isInRequest.set(false) - } + ) + response + } + }, "Edit Completion Request") + } finally { + isInRequest.set(false) + } + } } - } - - companion object { - - val instance by lazy { - log.info("Initializing OpenAI Client", Throwable()) - val client = IdeaOpenAIClient() - if (AppSettingsState.instance.apiLog) { - try { - val file = File(AppSettingsState.instance.pluginHome, "openai.log") - file.parentFile.mkdirs() - AppSettingsState.auxiliaryLog = file - client.logStreams.add(java.io.FileOutputStream(file, file.exists()).buffered()) - } catch (e: Exception) { - log.warn("Error initializing log file", e) + + override fun edit(editRequest: EditRequest): CompletionResponse { + lastEvent ?: return super.edit(editRequest) + if (isInRequest.getAndSet(true)) { + return super.edit(editRequest) + } else { + try { + if (!AppSettingsState.instance.editRequests) return super.edit(editRequest) + return withJsonDialog(editRequest, { request -> + UITools.run( + lastEvent!!.project, "OpenAI Request", true, suppressProgress = false + ) { + super.edit(request) + } + }, "Edit Edit Request") + } finally { + isInRequest.set(false) + } } - } - client } - var lastEvent: AnActionEvent? = null - private fun uiEdit( - project: Project? = null, - title: String = "Edit Request", - jsonTxt: String - ): String { - return execute { - val json = JTextArea( - /* text = */ "", - /* rows = */ 3, - /* columns = */ 120 - ) - json.isEditable = true - json.lineWrap = false - val jbScrollPane = JBScrollPane(json) - jbScrollPane.horizontalScrollBarPolicy = JBScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - jbScrollPane.verticalScrollBarPolicy = JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED - val dialog = object : DialogWrapper(project) { - init { - this.init() - this.title = title - this.setOKButtonText("OK") - this.setCancelButtonText("Cancel") - this.isResizable = true - } - - override fun createCenterPanel(): JPanel? { - val formBuilder = FormBuilder.createFormBuilder() - formBuilder.addLabeledComponentFillVertically("JSON", jbScrollPane) - return formBuilder.panel - } + companion object { + + val instance by lazy { + log.info("Initializing OpenAI Client", Throwable()) + val client = IdeaOpenAIClient() + if (AppSettingsState.instance.apiLog) { + try { + val file = File(AppSettingsState.instance.pluginHome, "openai.log") + file.parentFile.mkdirs() + AppSettingsState.auxiliaryLog = file + client.logStreams.add(java.io.FileOutputStream(file, file.exists()).buffered()) + } catch (e: Exception) { + log.warn("Error initializing log file", e) + } + } + client + } + + var lastEvent: AnActionEvent? = null + private fun uiEdit( + project: Project? = null, + title: String = "Edit Request", + jsonTxt: String + ): String { + return execute { + val json = JTextArea( + /* text = */ "", + /* rows = */ 3, + /* columns = */ 120 + ) + json.isEditable = true + json.lineWrap = false + val jbScrollPane = JBScrollPane(json) + jbScrollPane.horizontalScrollBarPolicy = JBScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED + jbScrollPane.verticalScrollBarPolicy = JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED + val dialog = object : DialogWrapper(project) { + init { + this.init() + this.title = title + this.setOKButtonText("OK") + this.setCancelButtonText("Cancel") + this.isResizable = true + } + + override fun createCenterPanel(): JPanel? { + val formBuilder = FormBuilder.createFormBuilder() + formBuilder.addLabeledComponentFillVertically("JSON", jbScrollPane) + return formBuilder.panel + } + } + json.text = jsonTxt + dialog.show() + log.warn("dialog.size = " + dialog.size) + if (!dialog.isOK) { + throw RuntimeException("Cancelled") + } + json.text + } ?: jsonTxt } - json.text = jsonTxt - dialog.show() - log.warn("dialog.size = " + dialog.size) - if (!dialog.isOK) { - throw RuntimeException("Cancelled") + + private fun execute( + fn: () -> T + ): T? { + val application = ApplicationManager.getApplication() + val ref: AtomicReference = AtomicReference() + if (null != application) { + application.invokeAndWait { ref.set(fn()) } + } else { + ref.set(fn()) + } + return ref.get() } - json.text - } ?: jsonTxt - } - private fun execute( - fn: () -> T - ): T? { - val application = ApplicationManager.getApplication() - val ref: AtomicReference = AtomicReference() - if (null != application) { - application.invokeAndWait { ref.set(fn()) } - } else { - ref.set(fn()) - } - return ref.get() - } + fun withJsonDialog( + request: T, + function: (T) -> V, + title: String + ): V { + val project = lastEvent?.project ?: return function(request) + return function(JsonUtil.fromJson(uiEdit(project, title, JsonUtil.toJson(request)), request::class.java)) + } - fun withJsonDialog( - request: T, - function: (T) -> V, - title: String - ): V { - val project = lastEvent?.project ?: return function(request) - return function(JsonUtil.fromJson(uiEdit(project, title, JsonUtil.toJson(request)), request::class.java)) + private val log = LoggerFactory.getLogger(IdeaOpenAIClient::class.java) + val currentSession = StorageInterface.newGlobalID() + val localUser = User(id = "1", email = "user@localhost") } - private val log = LoggerFactory.getLogger(IdeaOpenAIClient::class.java) - val currentSession = StorageInterface.newGlobalID() - val localUser = User(id = "1", email = "user@localhost") - } - } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/LineComment.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/LineComment.kt index 6908063d..49344579 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/LineComment.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/util/LineComment.kt @@ -12,8 +12,9 @@ class LineComment(private val commentPrefix: CharSequence, indent: CharSequence? override fun fromString(text: String?): LineComment { var textVar = text textVar = textVar!!.replace(Regex("\t"), TextBlock.TAB_REPLACEMENT.toString()) - val indent = getWhitespacePrefix(*textVar.split(TextBlock.DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray()) + val indent = + getWhitespacePrefix(*textVar.split(TextBlock.DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray()) return LineComment( commentPrefix, indent, diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/PluginStartupActivity.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/PluginStartupActivity.kt index 32ac1a0d..5c675282 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/PluginStartupActivity.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/util/PluginStartupActivity.kt @@ -1,13 +1,10 @@ package com.github.simiacryptus.aicoder.util -import com.github.simiacryptus.aicoder.actions.BaseAction import com.github.simiacryptus.aicoder.config.AppSettingsState import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.runReadAction -import com.intellij.openapi.application.runWriteAction -import com.intellij.openapi.project.Project import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.TextEditorWithPreview +import com.intellij.openapi.project.Project import com.intellij.openapi.startup.ProjectActivity import com.intellij.openapi.vfs.VirtualFileManager import com.simiacryptus.skyenet.core.OutputInterceptor @@ -31,7 +28,7 @@ class PluginStartupActivity : ProjectActivity { currentThread.contextClassLoader = prevClassLoader } - if (AppSettingsState.instance.showWelcomeScreen || AppSettingsState.instance.greetedVersion != AppSettingsState.CURRENT_VERSION) { + if (AppSettingsState.instance.showWelcomeScreen || AppSettingsState.instance.greetedVersion != AppSettingsState.CURRENT_VERSION) { val welcomeFile = "welcomePage.md" val resource = PluginStartupActivity::class.java.classLoader.getResource(welcomeFile) var virtualFile = resource?.let { VirtualFileManager.getInstance().findFileByUrl(it.toString()) } @@ -72,9 +69,9 @@ class PluginStartupActivity : ProjectActivity { log.error("Error opening welcome page", e) } } ?: log.error("Welcome page not found") - // Set showWelcomeScreen to false after showing it for the first time - AppSettingsState.instance.greetedVersion = AppSettingsState.CURRENT_VERSION - AppSettingsState.instance.showWelcomeScreen = false + // Set showWelcomeScreen to false after showing it for the first time + AppSettingsState.instance.greetedVersion = AppSettingsState.CURRENT_VERSION + AppSettingsState.instance.showWelcomeScreen = false } } catch (e: Exception) { log.error("Error during plugin startup", e) @@ -106,19 +103,6 @@ class PluginStartupActivity : ProjectActivity { ApplicationServices.isLocked = true } - private fun isFirstRun(): Boolean { - // Implement logic to determine if this is the first run after installation - // This could involve checking a persistent setting or a flag file - // For simplicity, assuming a function that checks this condition - return checkFirstRunFlag() - } - - private fun checkFirstRunFlag(): Boolean { - // Placeholder for actual implementation - // This should check a flag from persistent storage or settings - return true // Assuming it's the first run for example purposes - } - companion object { val log = org.slf4j.LoggerFactory.getLogger(PluginStartupActivity::class.java) diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/UITools.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/UITools.kt index 90f38d25..78dac42a 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/UITools.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/util/UITools.kt @@ -58,676 +58,676 @@ import kotlin.reflect.jvm.javaField import kotlin.reflect.jvm.javaType object UITools { - val retry = WeakHashMap() - - private val log = LoggerFactory.getLogger(UITools::class.java) - private val threadFactory: ThreadFactory = ThreadFactoryBuilder().setNameFormat("API Thread %d").build() - private val pool: ListeningExecutorService by lazy { - MoreExecutors.listeningDecorator( - ThreadPoolExecutor( - /* corePoolSize = */ AppSettingsState.instance.apiThreads, - /* maximumPoolSize = */AppSettingsState.instance.apiThreads, - /* keepAliveTime = */ 0L, - /* unit = */ TimeUnit.MILLISECONDS, - /* workQueue = */ LinkedBlockingQueue(), - /* threadFactory = */ threadFactory, - /* handler = */ ThreadPoolExecutor.AbortPolicy() - ) - ) - } - private val scheduledPool: ListeningScheduledExecutorService by lazy { - MoreExecutors.listeningDecorator(ScheduledThreadPoolExecutor(1, threadFactory)) - } - private val errorLog = mutableListOf>() - private val actionLog = mutableListOf() - private val singleThreadPool = Executors.newSingleThreadExecutor() - - fun redoableTask( - event: AnActionEvent, - request: Supplier, - ) { - log.debug("Starting redoableTask with event: ${event}, request: ${request}") - Futures.addCallback(pool.submit { - request.get() - }, futureCallback(event, request), pool) - log.debug("Submitted redoableTask for execution") - } - - private fun futureCallback( - event: AnActionEvent, - request: Supplier, - ) = object : FutureCallback { - override fun onSuccess(undo: Runnable) { - val requiredData = event.getData(CommonDataKeys.EDITOR) ?: return - val document = requiredData.document - retry[document] = getRetry(event, request, undo) - } - - override fun onFailure(t: Throwable) { - error(log, "Error", t) - } - } - - fun getRetry( - event: AnActionEvent, - request: Supplier, - undo: Runnable, - ): Runnable = Runnable { - Futures.addCallback( - pool.submit { - WriteCommandAction.runWriteCommandAction(event.project) { undo?.run() } - request.get() - }, futureCallback(event, request), pool - ) - } - - fun replaceString(document: Document, startOffset: Int, endOffset: Int, newText: CharSequence): Runnable { - log.debug("Invoking replaceString with startOffset: $startOffset, endOffset: $endOffset, newText: $newText") - val oldText: CharSequence = document.getText(TextRange(startOffset, endOffset)) - document.replaceString(startOffset, endOffset, newText) - logEdit( - String.format( - "FWD replaceString from %s to %s (%s->%s): %s", - startOffset, - endOffset, - endOffset - startOffset, - newText.length, - newText - ) - ) - return Runnable { - val verifyTxt = document.getText(TextRange(startOffset, startOffset + newText.length)) - log.debug("Verifying text after replaceString: expected: $newText, actual: $verifyTxt") - if (verifyTxt != newText) { - val msg = String.format( - "The text range from %d to %d does not match the expected text \"%s\" and is instead \"%s\"", - startOffset, - startOffset + newText.length, - newText, - verifyTxt + val retry = WeakHashMap() + + private val log = LoggerFactory.getLogger(UITools::class.java) + private val threadFactory: ThreadFactory = ThreadFactoryBuilder().setNameFormat("API Thread %d").build() + private val pool: ListeningExecutorService by lazy { + MoreExecutors.listeningDecorator( + ThreadPoolExecutor( + /* corePoolSize = */ AppSettingsState.instance.apiThreads, + /* maximumPoolSize = */AppSettingsState.instance.apiThreads, + /* keepAliveTime = */ 0L, + /* unit = */ TimeUnit.MILLISECONDS, + /* workQueue = */ LinkedBlockingQueue(), + /* threadFactory = */ threadFactory, + /* handler = */ ThreadPoolExecutor.AbortPolicy() + ) ) - log.error("Verification failed after replaceString: $msg") - throw IllegalStateException(msg) - } - document.replaceString(startOffset, startOffset + newText.length, oldText) - logEdit( - String.format( - "REV replaceString from %s to %s (%s->%s): %s", - startOffset, - startOffset + newText.length, - newText.length, - oldText.length, - oldText + } + private val scheduledPool: ListeningScheduledExecutorService by lazy { + MoreExecutors.listeningDecorator(ScheduledThreadPoolExecutor(1, threadFactory)) + } + private val errorLog = mutableListOf>() + private val actionLog = mutableListOf() + private val singleThreadPool = Executors.newSingleThreadExecutor() + + fun redoableTask( + event: AnActionEvent, + request: Supplier, + ) { + log.debug("Starting redoableTask with event: ${event}, request: ${request}") + Futures.addCallback(pool.submit { + request.get() + }, futureCallback(event, request), pool) + log.debug("Submitted redoableTask for execution") + } + + private fun futureCallback( + event: AnActionEvent, + request: Supplier, + ) = object : FutureCallback { + override fun onSuccess(undo: Runnable) { + val requiredData = event.getData(CommonDataKeys.EDITOR) ?: return + val document = requiredData.document + retry[document] = getRetry(event, request, undo) + } + + override fun onFailure(t: Throwable) { + error(log, "Error", t) + } + } + + fun getRetry( + event: AnActionEvent, + request: Supplier, + undo: Runnable, + ): Runnable = Runnable { + Futures.addCallback( + pool.submit { + WriteCommandAction.runWriteCommandAction(event.project) { undo.run() } + request.get() + }, futureCallback(event, request), pool ) - ) - } - } - - fun insertString(document: Document, startOffset: Int, newText: CharSequence): Runnable { - document.insertString(startOffset, newText) - logEdit(String.format("FWD insertString @ %s (%s): %s", startOffset, newText.length, newText)) - return Runnable { - val verifyTxt = document.getText(TextRange(startOffset, startOffset + newText.length)) - if (verifyTxt != newText) { - val message = String.format( - "The text range from %d to %d does not match the expected text \"%s\" and is instead \"%s\"", - startOffset, - startOffset + newText.length, - newText, - verifyTxt + } + + fun replaceString(document: Document, startOffset: Int, endOffset: Int, newText: CharSequence): Runnable { + log.debug("Invoking replaceString with startOffset: $startOffset, endOffset: $endOffset, newText: $newText") + val oldText: CharSequence = document.getText(TextRange(startOffset, endOffset)) + document.replaceString(startOffset, endOffset, newText) + logEdit( + String.format( + "FWD replaceString from %s to %s (%s->%s): %s", + startOffset, + endOffset, + endOffset - startOffset, + newText.length, + newText + ) + ) + return Runnable { + val verifyTxt = document.getText(TextRange(startOffset, startOffset + newText.length)) + log.debug("Verifying text after replaceString: expected: $newText, actual: $verifyTxt") + if (verifyTxt != newText) { + val msg = String.format( + "The text range from %d to %d does not match the expected text \"%s\" and is instead \"%s\"", + startOffset, + startOffset + newText.length, + newText, + verifyTxt + ) + log.error("Verification failed after replaceString: $msg") + throw IllegalStateException(msg) + } + document.replaceString(startOffset, startOffset + newText.length, oldText) + logEdit( + String.format( + "REV replaceString from %s to %s (%s->%s): %s", + startOffset, + startOffset + newText.length, + newText.length, + oldText.length, + oldText + ) + ) + } + } + + fun insertString(document: Document, startOffset: Int, newText: CharSequence): Runnable { + document.insertString(startOffset, newText) + logEdit(String.format("FWD insertString @ %s (%s): %s", startOffset, newText.length, newText)) + return Runnable { + val verifyTxt = document.getText(TextRange(startOffset, startOffset + newText.length)) + if (verifyTxt != newText) { + val message = String.format( + "The text range from %d to %d does not match the expected text \"%s\" and is instead \"%s\"", + startOffset, + startOffset + newText.length, + newText, + verifyTxt + ) + throw AssertionError(message) + } + document.deleteString(startOffset, startOffset + newText.length) + logEdit(String.format("REV deleteString from %s to %s", startOffset, startOffset + newText.length)) + } + } + + private fun logEdit(message: String) { + log.debug(message) + } + + @Suppress("unused") + fun deleteString(document: Document, startOffset: Int, endOffset: Int): Runnable { + val oldText: CharSequence = document.getText(TextRange(startOffset, endOffset)) + document.deleteString(startOffset, endOffset) + return Runnable { + document.insertString(startOffset, oldText) + logEdit(String.format("REV insertString @ %s (%s): %s", startOffset, oldText.length, oldText)) + } + } + + fun getIndent(caret: Caret?): CharSequence { + if (null == caret) return "" + val document = caret.editor.document + val documentText = document.text + val lineNumber = document.getLineNumber(caret.selectionStart) + val lines = documentText.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + if (lines.isEmpty()) return "" + return IndentedText.fromString(lines[max(lineNumber, 0).coerceAtMost(lines.size - 1)]).indent + } + + @Suppress("unused") + fun hasSelection(e: AnActionEvent): Boolean { + val caret = e.getData(CommonDataKeys.CARET) + return null != caret && caret.hasSelection() + } + + fun getIndent(event: AnActionEvent): CharSequence { + val caret = event.getData(CommonDataKeys.CARET) + val indent: CharSequence = if (null == caret) { + "" + } else { + getIndent(caret) + } + return indent + } + + fun readKotlinUIViaReflection(component: R, settings: T) { + val componentClass: Class<*> = component.javaClass + val declaredUIFields = componentClass.kotlin.memberProperties.map { it.name }.toSet() + for (settingsField in settings.javaClass.kotlin.memberProperties) { + if (settingsField is KMutableProperty<*>) { + settingsField.isAccessible = true + val settingsFieldName = settingsField.name + try { + var newSettingsValue: Any? = null + if (!declaredUIFields.contains(settingsFieldName)) continue + val uiField: KProperty1 = + (componentClass.kotlin.memberProperties.find { it.name == settingsFieldName } as KProperty1?)!! + var uiVal = uiField.get(component) + if (uiVal is JScrollPane) { + uiVal = uiVal.viewport.view + } + when (settingsField.returnType.javaType.typeName) { + "java.lang.String" -> if (uiVal is JTextComponent) { + newSettingsValue = uiVal.text + } else if (uiVal is ComboBox<*>) { + newSettingsValue = uiVal.item + } + + "int", "java.lang.Integer" -> if (uiVal is JTextComponent) { + newSettingsValue = if (uiVal.text.isBlank()) -1 else uiVal.text.toInt() + } + + "long" -> if (uiVal is JTextComponent) { + newSettingsValue = if (uiVal.text.isBlank()) -1 else uiVal.text.toLong() + } + + "double", "java.lang.Double" -> if (uiVal is JTextComponent) { + newSettingsValue = if (uiVal.text.isBlank()) 0.0 else uiVal.text.toDouble() + } + + "boolean" -> if (uiVal is JCheckBox) { + newSettingsValue = uiVal.isSelected + } else if (uiVal is JTextComponent) { + newSettingsValue = java.lang.Boolean.parseBoolean(uiVal.text) + } + + else -> if (Enum::class.java.isAssignableFrom(settingsField.returnType.javaType as Class<*>)) { + if (uiVal is ComboBox<*>) { + val comboBox = uiVal + val item = comboBox.item + val enumClass = settingsField.returnType.javaType as Class?> + val string = item.toString() + newSettingsValue = findValue(enumClass, string) + } + } + } + settingsField.setter.call(settings, newSettingsValue) + } catch (e: Throwable) { + throw RuntimeException("Error processing $settingsField", e) + } + } + } + } + + private fun findValue(enumClass: Class?>, string: String): Enum<*>? { + enumClass.enumConstants?.filter { it?.name?.compareTo(string, true) == 0 }?.forEach { return it } + return java.lang.Enum.valueOf( + enumClass, string ) - throw AssertionError(message) - } - document.deleteString(startOffset, startOffset + newText.length) - logEdit(String.format("REV deleteString from %s to %s", startOffset, startOffset + newText.length)) - } - } - - private fun logEdit(message: String) { - log.debug(message) - } - - @Suppress("unused") - fun deleteString(document: Document, startOffset: Int, endOffset: Int): Runnable { - val oldText: CharSequence = document.getText(TextRange(startOffset, endOffset)) - document.deleteString(startOffset, endOffset) - return Runnable { - document.insertString(startOffset, oldText) - logEdit(String.format("REV insertString @ %s (%s): %s", startOffset, oldText.length, oldText)) - } - } - - fun getIndent(caret: Caret?): CharSequence { - if (null == caret) return "" - val document = caret.editor.document - val documentText = document.text - val lineNumber = document.getLineNumber(caret.selectionStart) - val lines = documentText.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - if (lines.isEmpty()) return "" - return IndentedText.fromString(lines[max(lineNumber, 0).coerceAtMost(lines.size - 1)]).indent - } - - @Suppress("unused") - fun hasSelection(e: AnActionEvent): Boolean { - val caret = e.getData(CommonDataKeys.CARET) - return null != caret && caret.hasSelection() - } - - fun getIndent(event: AnActionEvent): CharSequence { - val caret = event.getData(CommonDataKeys.CARET) - val indent: CharSequence = if (null == caret) { - "" - } else { - getIndent(caret) - } - return indent - } - - fun readKotlinUIViaReflection(component: R, settings: T) { - val componentClass: Class<*> = component.javaClass - val declaredUIFields = componentClass.kotlin.memberProperties.map { it.name }.toSet() - for (settingsField in settings.javaClass.kotlin.memberProperties) { - if (settingsField is KMutableProperty<*>) { - settingsField.isAccessible = true - val settingsFieldName = settingsField.name - try { - var newSettingsValue: Any? = null - if (!declaredUIFields.contains(settingsFieldName)) continue - val uiField: KProperty1 = - (componentClass.kotlin.memberProperties.find { it.name == settingsFieldName } as KProperty1?)!! - var uiVal = uiField.get(component) - if (uiVal is JScrollPane) { - uiVal = uiVal.viewport.view - } - when (settingsField.returnType.javaType.typeName) { - "java.lang.String" -> if (uiVal is JTextComponent) { - newSettingsValue = uiVal.text - } else if (uiVal is ComboBox<*>) { - newSettingsValue = uiVal.item + } + + fun writeKotlinUIViaReflection(settings: T, component: R) { + val componentClass: Class<*> = component.javaClass + val declaredUIFields = componentClass.kotlin.memberProperties.map { it.name }.toSet() + val memberProperties = settings.javaClass.kotlin.memberProperties + val publicProperties = memberProperties.filter { + it.visibility == KVisibility.PUBLIC //&& it is KMutableProperty<*> + } + for (settingsField in publicProperties) { + val fieldName = settingsField.name + try { + if (!declaredUIFields.contains(fieldName)) { + log.warn("Field not found: $fieldName") + continue + } + val uiField: KProperty1 = + (componentClass.kotlin.memberProperties.find { it.name == fieldName } as KProperty1?)!! + val settingsVal = settingsField.get(settings) ?: continue + var uiVal = uiField.get(component) + if (uiVal is JScrollPane) { + uiVal = uiVal.viewport.view + } + when (settingsField.returnType.javaType.typeName) { + "java.lang.String" -> if (uiVal is JTextComponent) { + uiVal.text = settingsVal.toString() + } else if (uiVal is ComboBox<*>) { + (uiVal as ComboBox).item = settingsVal.toString() + } + + "int", "java.lang.Integer" -> if (uiVal is JTextComponent) { + uiVal.text = (settingsVal as Int).toString() + } + + "long" -> if (uiVal is JTextComponent) { + uiVal.text = (settingsVal as Int).toLong().toString() + } + + "boolean" -> if (uiVal is JCheckBox) { + uiVal.isSelected = (settingsVal as Boolean) + } else if (uiVal is JTextComponent) { + uiVal.text = java.lang.Boolean.toString((settingsVal as Boolean)) + } + + "double", "java.lang.Double" -> if (uiVal is JTextComponent) { + uiVal.text = (settingsVal as Double).toString() + } + + else -> if (uiVal is ComboBox<*>) { + (uiVal as ComboBox).item = settingsVal.toString() + } + } + } catch (e: Throwable) { + throw RuntimeException("Error processing $settingsField", e) } + } + } - "int", "java.lang.Integer" -> if (uiVal is JTextComponent) { - newSettingsValue = if (uiVal.text.isBlank()) -1 else uiVal.text.toInt() + private fun addKotlinFields(ui: T, formBuilder: FormBuilder, fillVertically: Boolean) { + var first = true + for (field in ui.javaClass.kotlin.memberProperties) { + if (field.javaField == null) continue + try { + val nameAnnotation = field.annotations.find { it is Name } as Name? + val component = field.get(ui) as JComponent + if (nameAnnotation != null) { + if (first && fillVertically) { + first = false + formBuilder.addLabeledComponentFillVertically(nameAnnotation.value + ": ", component) + } else { + formBuilder.addLabeledComponent(JBLabel(nameAnnotation.value + ": "), component, 1, false) + } + } else { + formBuilder.addComponentToRightColumn(component, 1) + } + } catch (e: IllegalAccessException) { + throw RuntimeException(e) + } catch (e: Throwable) { + error(log, "Error processing " + field.name, e) } + } + } + + private fun getMaximumSize(factor: Double): Dimension { + val screenSize = Toolkit.getDefaultToolkit().screenSize + return Dimension((screenSize.getWidth() * factor).toInt(), (screenSize.getHeight() * factor).toInt()) + } + + private fun showOptionDialog(mainPanel: JPanel?, vararg options: Any, title: String, modal: Boolean = true): Int { + val pane = getOptionPane(mainPanel, options) + val rootFrame = JOptionPane.getRootFrame() + pane.componentOrientation = rootFrame.componentOrientation + val dialog = JDialog(rootFrame, title, modal) + dialog.componentOrientation = rootFrame.componentOrientation + + val latch = if (!modal) CountDownLatch(1) else null + configure(dialog, pane, latch) + dialog.isVisible = true + if (!modal) latch?.await() + + dialog.dispose() + return getSelectedValue(pane, options) + } + + private fun getOptionPane( + mainPanel: JPanel?, + options: Array, + ): JOptionPane { + val pane = JOptionPane( + mainPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.NO_OPTION, null, options, options[0] + ) + pane.initialValue = options[0] + return pane + } + + private fun configure(dialog: JDialog, pane: JOptionPane, latch: CountDownLatch? = null) { + val contentPane = dialog.contentPane + contentPane.layout = BorderLayout() + contentPane.add(pane, BorderLayout.CENTER) - "long" -> if (uiVal is JTextComponent) { - newSettingsValue = if (uiVal.text.isBlank()) -1 else uiVal.text.toLong() + if (JDialog.isDefaultLookAndFeelDecorated() && UIManager.getLookAndFeel().supportsWindowDecorations) { + dialog.isUndecorated = true + pane.rootPane.windowDecorationStyle = JRootPane.PLAIN_DIALOG + } + dialog.isResizable = true + dialog.maximumSize = getMaximumSize(0.9) + dialog.pack() + dialog.setLocationRelativeTo(null as Component?) + val adapter: WindowAdapter = windowAdapter(pane, dialog) + dialog.addWindowListener(adapter) + dialog.addWindowFocusListener(adapter) + dialog.addComponentListener(object : ComponentAdapter() { + override fun componentShown(ce: ComponentEvent) { + // reset value to ensure closing works properly + pane.value = JOptionPane.UNINITIALIZED_VALUE + } + }) + pane.addPropertyChangeListener { event: PropertyChangeEvent -> + if (dialog.isVisible && event.source === pane && event.propertyName == JOptionPane.VALUE_PROPERTY && event.newValue != null && event.newValue !== JOptionPane.UNINITIALIZED_VALUE) { + dialog.isVisible = false + latch?.countDown() } + } + + pane.selectInitialValue() + } - "double", "java.lang.Double" -> if (uiVal is JTextComponent) { - newSettingsValue = if (uiVal.text.isBlank()) 0.0 else uiVal.text.toDouble() + private fun windowAdapter(pane: JOptionPane, dialog: JDialog): WindowAdapter { + val adapter: WindowAdapter = object : WindowAdapter() { + private var gotFocus = false + override fun windowClosing(we: WindowEvent) { + pane.value = null } - "boolean" -> if (uiVal is JCheckBox) { - newSettingsValue = uiVal.isSelected - } else if (uiVal is JTextComponent) { - newSettingsValue = java.lang.Boolean.parseBoolean(uiVal.text) + override fun windowClosed(e: WindowEvent) { + pane.removePropertyChangeListener { event: PropertyChangeEvent -> + if (dialog.isVisible && event.source === pane && event.propertyName == JOptionPane.VALUE_PROPERTY && event.newValue != null && event.newValue !== JOptionPane.UNINITIALIZED_VALUE) { + dialog.isVisible = false + } + } + dialog.contentPane.removeAll() } - else -> if (Enum::class.java.isAssignableFrom(settingsField.returnType.javaType as Class<*>)) { - if (uiVal is ComboBox<*>) { - val comboBox = uiVal - val item = comboBox.item - val enumClass = settingsField.returnType.javaType as Class?> - val string = item.toString() - newSettingsValue = findValue(enumClass, string) - } + override fun windowGainedFocus(we: WindowEvent) { + if (!gotFocus) { + pane.selectInitialValue() + gotFocus = true + } } - } - settingsField.setter.call(settings, newSettingsValue) - } catch (e: Throwable) { - throw RuntimeException("Error processing $settingsField", e) } - } + return adapter } - } - private fun findValue(enumClass: Class?>, string: String): Enum<*>? { - enumClass.enumConstants?.filter { it?.name?.compareTo(string, true) == 0 }?.forEach { return it } - return java.lang.Enum.valueOf( - enumClass, string - ) - } - - fun writeKotlinUIViaReflection(settings: T, component: R) { - val componentClass: Class<*> = component.javaClass - val declaredUIFields = componentClass.kotlin.memberProperties.map { it.name }.toSet() - val memberProperties = settings.javaClass.kotlin.memberProperties - val publicProperties = memberProperties.filter { - it.visibility == KVisibility.PUBLIC //&& it is KMutableProperty<*> - } - for (settingsField in publicProperties) { - val fieldName = settingsField.name - try { - if (!declaredUIFields.contains(fieldName)) { - log.warn("Field not found: $fieldName") - continue + private fun getSelectedValue(pane: JOptionPane, options: Array): Int { + val selectedValue = pane.value ?: return JOptionPane.CLOSED_OPTION + var counter = 0 + val maxCounter = options.size + while (counter < maxCounter) { + if (options[counter] == selectedValue) return counter + counter++ } - val uiField: KProperty1 = - (componentClass.kotlin.memberProperties.find { it.name == fieldName } as KProperty1?)!! - val settingsVal = settingsField.get(settings) ?: continue - var uiVal = uiField.get(component) - if (uiVal is JScrollPane) { - uiVal = uiVal.viewport.view + return JOptionPane.CLOSED_OPTION + } + + private fun wrapScrollPane(promptArea: JBTextArea?): JBScrollPane { + val scrollPane = JBScrollPane(promptArea) + scrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED + scrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED + return scrollPane + } + + fun showCheckboxDialog( + promptMessage: String, + checkboxIds: Array, + checkboxDescriptions: Array, + ): Array { + val formBuilder = FormBuilder.createFormBuilder() + val checkboxMap = HashMap() + for (i in checkboxIds.indices) { + val checkbox = JCheckBox(checkboxDescriptions[i], null as Icon?, true) + checkboxMap[checkboxIds[i]] = checkbox + formBuilder.addComponent(checkbox) } - when (settingsField.returnType.javaType.typeName) { - "java.lang.String" -> if (uiVal is JTextComponent) { - uiVal.text = settingsVal.toString() - } else if (uiVal is ComboBox<*>) { - (uiVal as ComboBox).item = settingsVal.toString() - } - - "int", "java.lang.Integer" -> if (uiVal is JTextComponent) { - uiVal.text = (settingsVal as Int).toString() - } - - "long" -> if (uiVal is JTextComponent) { - uiVal.text = (settingsVal as Int).toLong().toString() - } - - "boolean" -> if (uiVal is JCheckBox) { - uiVal.isSelected = (settingsVal as Boolean) - } else if (uiVal is JTextComponent) { - uiVal.text = java.lang.Boolean.toString((settingsVal as Boolean)) - } - - "double", "java.lang.Double" -> if (uiVal is JTextComponent) { - uiVal.text = (settingsVal as Double).toString() - } - - else -> if (uiVal is ComboBox<*>) { - (uiVal as ComboBox).item = settingsVal.toString() - } + val dialogResult = showOptionDialog(formBuilder.panel, "OK", title = promptMessage) + val selectedIds = ArrayList() + if (dialogResult == 0) { + for ((checkboxId, checkbox) in checkboxMap) { + if (checkbox.isSelected) { + selectedIds.add(checkboxId) + } + } } - } catch (e: Throwable) { - throw RuntimeException("Error processing $settingsField", e) - } - } - } - - private fun addKotlinFields(ui: T, formBuilder: FormBuilder, fillVertically: Boolean) { - var first = true - for (field in ui.javaClass.kotlin.memberProperties) { - if (field.javaField == null) continue - try { - val nameAnnotation = field.annotations.find { it is Name } as Name? - val component = field.get(ui) as JComponent - if (nameAnnotation != null) { - if (first && fillVertically) { - first = false - formBuilder.addLabeledComponentFillVertically(nameAnnotation.value + ": ", component) - } else { - formBuilder.addLabeledComponent(JBLabel(nameAnnotation.value + ": "), component, 1, false) - } - } else { - formBuilder.addComponentToRightColumn(component, 1) + return selectedIds.toTypedArray() + } + + fun showRadioButtonDialog( + promptMessage: CharSequence, + vararg radioButtonDescriptions: CharSequence, + ): CharSequence? { + val formBuilder = FormBuilder.createFormBuilder() + val radioButtonMap = HashMap() + val buttonGroup = ButtonGroup() + for (i in radioButtonDescriptions.indices) { + val radioButton = JRadioButton(radioButtonDescriptions[i].toString(), null as Icon?, true) + radioButtonMap[radioButtonDescriptions[i].toString()] = radioButton + buttonGroup.add(radioButton) + formBuilder.addComponent(radioButton) } - } catch (e: IllegalAccessException) { - throw RuntimeException(e) - } catch (e: Throwable) { - error(log, "Error processing " + field.name, e) - } - } - } - - private fun getMaximumSize(factor: Double): Dimension { - val screenSize = Toolkit.getDefaultToolkit().screenSize - return Dimension((screenSize.getWidth() * factor).toInt(), (screenSize.getHeight() * factor).toInt()) - } - - private fun showOptionDialog(mainPanel: JPanel?, vararg options: Any, title: String, modal: Boolean = true): Int { - val pane = getOptionPane(mainPanel, options) - val rootFrame = JOptionPane.getRootFrame() - pane.componentOrientation = rootFrame.componentOrientation - val dialog = JDialog(rootFrame, title, modal) - dialog.componentOrientation = rootFrame.componentOrientation - - val latch = if (!modal) CountDownLatch(1) else null - configure(dialog, pane, latch) - dialog.isVisible = true - if (!modal) latch?.await() - - dialog.dispose() - return getSelectedValue(pane, options) - } - - private fun getOptionPane( - mainPanel: JPanel?, - options: Array, - ): JOptionPane { - val pane = JOptionPane( - mainPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.NO_OPTION, null, options, options[0] + val dialogResult = showOptionDialog(formBuilder.panel, "OK", title = promptMessage.toString()) + if (dialogResult == 0) { + for ((radioButtonId, radioButton) in radioButtonMap) { + if (radioButton.isSelected) { + return radioButtonId + } + } + } + return null + } + + fun buildFormViaReflection( + component: T, + fillVertically: Boolean = true, + formBuilder: FormBuilder = FormBuilder.createFormBuilder(), + ): JPanel? { + addKotlinFields(component, formBuilder, fillVertically) + return formBuilder.addComponentFillVertically(JPanel(), 0).panel + } + + fun showDialog( + project: Project?, + uiClass: Class, + configClass: Class, + title: String = "Generate Project", + onComplete: (C) -> Unit = { _ -> }, + ): C = showDialog( + project, + uiClass.getConstructor().newInstance(), + configClass.getConstructor().newInstance(), + title, + onComplete ) - pane.initialValue = options[0] - return pane - } - - private fun configure(dialog: JDialog, pane: JOptionPane, latch: CountDownLatch? = null) { - val contentPane = dialog.contentPane - contentPane.layout = BorderLayout() - contentPane.add(pane, BorderLayout.CENTER) - - if (JDialog.isDefaultLookAndFeelDecorated() && UIManager.getLookAndFeel().supportsWindowDecorations) { - dialog.isUndecorated = true - pane.rootPane.windowDecorationStyle = JRootPane.PLAIN_DIALOG - } - dialog.isResizable = true - dialog.maximumSize = getMaximumSize(0.9) - dialog.pack() - dialog.setLocationRelativeTo(null as Component?) - val adapter: WindowAdapter = windowAdapter(pane, dialog) - dialog.addWindowListener(adapter) - dialog.addWindowFocusListener(adapter) - dialog.addComponentListener(object : ComponentAdapter() { - override fun componentShown(ce: ComponentEvent) { - // reset value to ensure closing works properly - pane.value = JOptionPane.UNINITIALIZED_VALUE - } - }) - pane.addPropertyChangeListener { event: PropertyChangeEvent -> - if (dialog.isVisible && event.source === pane && event.propertyName == JOptionPane.VALUE_PROPERTY && event.newValue != null && event.newValue !== JOptionPane.UNINITIALIZED_VALUE) { - dialog.isVisible = false - latch?.countDown() - } - } - - pane.selectInitialValue() - } - - private fun windowAdapter(pane: JOptionPane, dialog: JDialog): WindowAdapter { - val adapter: WindowAdapter = object : WindowAdapter() { - private var gotFocus = false - override fun windowClosing(we: WindowEvent) { - pane.value = null - } - - override fun windowClosed(e: WindowEvent) { - pane.removePropertyChangeListener { event: PropertyChangeEvent -> - if (dialog.isVisible && event.source === pane && event.propertyName == JOptionPane.VALUE_PROPERTY && event.newValue != null && event.newValue !== JOptionPane.UNINITIALIZED_VALUE) { - dialog.isVisible = false - } + + fun showDialog( + project: Project?, + component: T, + config: C, + title: String, + onComplete: (C) -> Unit + ): C { + log.debug("Showing dialog with title: $title") + val dialog = object : DialogWrapper(project) { + init { + this.init() + this.title = title + this.setOKButtonText("Generate") + this.setCancelButtonText("Cancel") + this.isResizable = true + //this.setPreferredFocusedComponent(this) + //this.setContent(this) + } + + override fun createCenterPanel(): JComponent? { + log.debug("Creating center panel for dialog") + return buildFormViaReflection(component) + } + } + dialog.show() + log.debug("Dialog shown with result: ${dialog.isOK}") + if (dialog.isOK) { + readKotlinUIViaReflection(component, config) + log.debug("Reading UI via reflection completed") + onComplete(config) + log.debug("onComplete callback executed") + } + return config + } + + fun getSelectedFolder(e: AnActionEvent): VirtualFile? { + val dataContext = e.dataContext + val data = PlatformDataKeys.VIRTUAL_FILE.getData(dataContext) + if (data != null && data.isDirectory) { + return data + } + val editor = PlatformDataKeys.EDITOR.getData(dataContext) + if (editor != null) { + val file = FileDocumentManager.getInstance().getFile(editor.document) + if (file != null) { + return file.parent + } + } + return null + } + + fun getSelectedFile(e: AnActionEvent): VirtualFile? { + val dataContext = e.dataContext + val data = PlatformDataKeys.VIRTUAL_FILE.getData(dataContext) + if (data != null && !data.isDirectory) { + return data } - dialog.contentPane.removeAll() - } + val editor = PlatformDataKeys.EDITOR.getData(dataContext) + if (editor != null) { + val file = FileDocumentManager.getInstance().getFile(editor.document) + if (file != null) { + return file + } + } + return null + } + + fun writeableFn( + event: AnActionEvent, + fn: () -> Runnable, + ): Runnable { + val runnable = AtomicReference() + WriteCommandAction.runWriteCommandAction(event.project) { runnable.set(fn()) } + return runnable.get() + } - override fun windowGainedFocus(we: WindowEvent) { - if (!gotFocus) { - pane.selectInitialValue() - gotFocus = true + class ModalTask( + project: Project, title: String, canBeCancelled: Boolean, val task: (ProgressIndicator) -> T + ) : Task.WithResult(project, title, canBeCancelled), Supplier { + private val result = AtomicReference() + private val isError = AtomicBoolean(false) + private val error = AtomicReference() + private val semaphore = Semaphore(0) + override fun compute(indicator: ProgressIndicator): T? { + val currentThread = Thread.currentThread() + val threads = ArrayList() + val scheduledFuture = scheduledPool.scheduleAtFixedRate({ + if (indicator.isCanceled) { + threads.forEach { it.interrupt() } + } + }, 0, 1, TimeUnit.SECONDS) + threads.add(currentThread) + return try { + result.set(task(indicator)) + result.get() + } catch (e: Throwable) { + error(log, "Error running task", e) + isError.set(true) + error.set(e) + null + } finally { + semaphore.release() + threads.remove(currentThread) + scheduledFuture.cancel(true) + } } - } - } - return adapter - } - - private fun getSelectedValue(pane: JOptionPane, options: Array): Int { - val selectedValue = pane.value ?: return JOptionPane.CLOSED_OPTION - var counter = 0 - val maxCounter = options.size - while (counter < maxCounter) { - if (options[counter] == selectedValue) return counter - counter++ - } - return JOptionPane.CLOSED_OPTION - } - - private fun wrapScrollPane(promptArea: JBTextArea?): JBScrollPane { - val scrollPane = JBScrollPane(promptArea) - scrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - scrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED - return scrollPane - } - - fun showCheckboxDialog( - promptMessage: String, - checkboxIds: Array, - checkboxDescriptions: Array, - ): Array { - val formBuilder = FormBuilder.createFormBuilder() - val checkboxMap = HashMap() - for (i in checkboxIds.indices) { - val checkbox = JCheckBox(checkboxDescriptions[i], null as Icon?, true) - checkboxMap[checkboxIds[i]] = checkbox - formBuilder.addComponent(checkbox) - } - val dialogResult = showOptionDialog(formBuilder.panel, "OK", title = promptMessage) - val selectedIds = ArrayList() - if (dialogResult == 0) { - for ((checkboxId, checkbox) in checkboxMap) { - if (checkbox.isSelected) { - selectedIds.add(checkboxId) + + override fun get(): T { + semaphore.acquire() + semaphore.release() + if (isError.get()) { + throw error.get() + } + return result.get() } - } - } - return selectedIds.toTypedArray() - } - - fun showRadioButtonDialog( - promptMessage: CharSequence, - vararg radioButtonDescriptions: CharSequence, - ): CharSequence? { - val formBuilder = FormBuilder.createFormBuilder() - val radioButtonMap = HashMap() - val buttonGroup = ButtonGroup() - for (i in radioButtonDescriptions.indices) { - val radioButton = JRadioButton(radioButtonDescriptions[i].toString(), null as Icon?, true) - radioButtonMap[radioButtonDescriptions[i].toString()] = radioButton - buttonGroup.add(radioButton) - formBuilder.addComponent(radioButton) - } - val dialogResult = showOptionDialog(formBuilder.panel, "OK", title = promptMessage.toString()) - if (dialogResult == 0) { - for ((radioButtonId, radioButton) in radioButtonMap) { - if (radioButton.isSelected) { - return radioButtonId + + } + + class BgTask( + project: Project, title: String, canBeCancelled: Boolean, val task: (ProgressIndicator) -> T + ) : Task.Backgroundable(project, title, canBeCancelled, DEAF), Supplier { + + private val result = AtomicReference() + private val isError = AtomicBoolean(false) + private val error = AtomicReference() + private val semaphore = Semaphore(0) + override fun run(indicator: ProgressIndicator) { + val currentThread = Thread.currentThread() + val threads = ArrayList() + val scheduledFuture = scheduledPool.scheduleAtFixedRate({ + if (indicator.isCanceled) { + threads.forEach { it.interrupt() } + } + }, 0, 1, TimeUnit.SECONDS) + threads.add(currentThread) + try { + val result = task(indicator) + this.result.set(result) + } catch (e: Throwable) { + error(log, "Error running task", e) + error.set(e) + isError.set(true) + } finally { + semaphore.release() + threads.remove(currentThread) + scheduledFuture.cancel(true) + } } - } - } - return null - } - - fun buildFormViaReflection( - component: T, - fillVertically: Boolean = true, - formBuilder: FormBuilder = FormBuilder.createFormBuilder(), - ): JPanel? { - addKotlinFields(component, formBuilder, fillVertically) - return formBuilder.addComponentFillVertically(JPanel(), 0).panel - } - - fun showDialog( - project: Project?, - uiClass: Class, - configClass: Class, - title: String = "Generate Project", - onComplete: (C) -> Unit = { _ -> }, - ): C = showDialog( - project, - uiClass.getConstructor().newInstance(), - configClass.getConstructor().newInstance(), - title, - onComplete - ) - - fun showDialog( - project: Project?, - component: T, - config: C, - title: String, - onComplete: (C) -> Unit - ): C { - log.debug("Showing dialog with title: $title") - val dialog = object : DialogWrapper(project) { - init { - this.init() - this.title = title - this.setOKButtonText("Generate") - this.setCancelButtonText("Cancel") - this.isResizable = true - //this.setPreferredFocusedComponent(this) - //this.setContent(this) - } - - override fun createCenterPanel(): JComponent? { - log.debug("Creating center panel for dialog") - return buildFormViaReflection(component) - } - } - dialog.show() - log.debug("Dialog shown with result: ${dialog.isOK}") - if (dialog.isOK) { - readKotlinUIViaReflection(component, config) - log.debug("Reading UI via reflection completed") - onComplete(config) - log.debug("onComplete callback executed") - } - return config - } - - fun getSelectedFolder(e: AnActionEvent): VirtualFile? { - val dataContext = e.dataContext - val data = PlatformDataKeys.VIRTUAL_FILE.getData(dataContext) - if (data != null && data.isDirectory) { - return data - } - val editor = PlatformDataKeys.EDITOR.getData(dataContext) - if (editor != null) { - val file = FileDocumentManager.getInstance().getFile(editor.document) - if (file != null) { - return file.parent - } - } - return null - } - - fun getSelectedFile(e: AnActionEvent): VirtualFile? { - val dataContext = e.dataContext - val data = PlatformDataKeys.VIRTUAL_FILE.getData(dataContext) - if (data != null && !data.isDirectory) { - return data - } - val editor = PlatformDataKeys.EDITOR.getData(dataContext) - if (editor != null) { - val file = FileDocumentManager.getInstance().getFile(editor.document) - if (file != null) { - return file - } - } - return null - } - - fun writeableFn( - event: AnActionEvent, - fn: () -> Runnable, - ): Runnable { - val runnable = AtomicReference() - WriteCommandAction.runWriteCommandAction(event.project) { runnable.set(fn()) } - return runnable.get() - } - - class ModalTask( - project: Project, title: String, canBeCancelled: Boolean, val task: (ProgressIndicator) -> T - ) : Task.WithResult(project, title, canBeCancelled), Supplier { - private val result = AtomicReference() - private val isError = AtomicBoolean(false) - private val error = AtomicReference() - private val semaphore = Semaphore(0) - override fun compute(indicator: ProgressIndicator): T? { - val currentThread = Thread.currentThread() - val threads = ArrayList() - val scheduledFuture = scheduledPool.scheduleAtFixedRate({ - if (indicator.isCanceled) { - threads.forEach { it.interrupt() } + + override fun get(): T { + semaphore.acquire() + semaphore.release() + if (isError.get()) { + throw error.get() + } + return result.get() } - }, 0, 1, TimeUnit.SECONDS) - threads.add(currentThread) - return try { - result.set(task(indicator)) - result.get() - } catch (e: Throwable) { - error(log, "Error running task", e) - isError.set(true) - error.set(e) - null - } finally { - semaphore.release() - threads.remove(currentThread) - scheduledFuture.cancel(true) - } - } - - override fun get(): T { - semaphore.acquire() - semaphore.release() - if (isError.get()) { - throw error.get() - } - return result.get() - } - - } - - class BgTask( - project: Project, title: String, canBeCancelled: Boolean, val task: (ProgressIndicator) -> T - ) : Task.Backgroundable(project, title, canBeCancelled, DEAF), Supplier { - - private val result = AtomicReference() - private val isError = AtomicBoolean(false) - private val error = AtomicReference() - private val semaphore = Semaphore(0) - override fun run(indicator: ProgressIndicator) { - val currentThread = Thread.currentThread() - val threads = ArrayList() - val scheduledFuture = scheduledPool.scheduleAtFixedRate({ - if (indicator.isCanceled) { - threads.forEach { it.interrupt() } + } + + fun run( + project: Project?, + title: String?, + canBeCancelled: Boolean = true, + suppressProgress: Boolean = true, + task: (ProgressIndicator) -> T, + ): T { + return if (project == null || suppressProgress == AppSettingsState.instance.editRequests) { + checkApiKey() + task(AbstractProgressIndicatorBase()) + } else { + checkApiKey() + val t = if (AppSettingsState.instance.modalTasks) ModalTask(project, title ?: "", canBeCancelled, task) + else BgTask(project, title ?: "", canBeCancelled, task) + ProgressManager.getInstance().run(t) + t.get() } - }, 0, 1, TimeUnit.SECONDS) - threads.add(currentThread) - try { - val result = task(indicator) - this.result.set(result) - } catch (e: Throwable) { - error(log, "Error running task", e) - error.set(e) - isError.set(true) - } finally { - semaphore.release() - threads.remove(currentThread) - scheduledFuture.cancel(true) - } - } - - override fun get(): T { - semaphore.acquire() - semaphore.release() - if (isError.get()) { - throw error.get() - } - return result.get() - } - } - - fun run( - project: Project?, - title: String?, - canBeCancelled: Boolean = true, - suppressProgress: Boolean = true, - task: (ProgressIndicator) -> T, - ): T { - return if (project == null || suppressProgress == AppSettingsState.instance.editRequests) { - checkApiKey() - task(AbstractProgressIndicatorBase()) - } else { - checkApiKey() - val t = if (AppSettingsState.instance.modalTasks) ModalTask(project, title ?: "", canBeCancelled, task) - else BgTask(project, title ?: "", canBeCancelled, task) - ProgressManager.getInstance().run(t) - t.get() - } - } - - fun checkApiKey(k: String = AppSettingsState.instance.apiKey?.values?.first() ?: ""): String { + } + + fun checkApiKey(k: String = AppSettingsState.instance.apiKey?.values?.first() ?: ""): String { // var key = k // if (key.isEmpty() || key != AppSettingsState.instance.apiKey) { // synchronized(OpenAIClient::class.java) { @@ -738,103 +738,107 @@ object UITools { // } // } // } - return k - } - - - fun map( - moderateAsync: ListenableFuture, - o: com.google.common.base.Function, - ): ListenableFuture = Futures.transform(moderateAsync, o::apply, pool) - - - fun logAction(message: String) { - actionLog += message - } + return k + } - fun error(log: org.slf4j.Logger, msg: String, e: Throwable) { - log?.error(msg, e) - errorLog += Pair(msg, e) - singleThreadPool.submit { - if (AppSettingsState.instance.suppressErrors) { - return@submit - } else if (e.matches { ModerationException::class.java.isAssignableFrom(it.javaClass) }) { - JOptionPane.showMessageDialog( - null, e.message, "This request was rejected by OpenAI Moderation", JOptionPane.WARNING_MESSAGE - ) - } else if (e.matches { - java.lang.InterruptedException::class.java.isAssignableFrom(it.javaClass) && it.message?.contains( - "sleep interrupted" - ) == true - }) { - JOptionPane.showMessageDialog( - null, "This request was cancelled by the user", "User Cancelled Request", JOptionPane.WARNING_MESSAGE - ) - } else if (e.matches { IOException::class.java.isAssignableFrom(it.javaClass) && it.message?.contains("Incorrect API key") == true }) { + fun map( + moderateAsync: ListenableFuture, + o: com.google.common.base.Function, + ): ListenableFuture = Futures.transform(moderateAsync, o::apply, pool) - val formBuilder = FormBuilder.createFormBuilder() - formBuilder.addLabeledComponent( - "Error", JLabel("The API key was rejected by the server.") - ) + fun logAction(message: String) { + actionLog += message + } - val apiKeyInput = JBPasswordField() - //bugReportTextArea.rows = 40 - apiKeyInput.columns = 80 - apiKeyInput.isEditable = true - //apiKeyInput.text = """""".trimMargin() - formBuilder.addLabeledComponent("API Key", apiKeyInput) - val openAccountButton = JXButton("Open Account Page") - openAccountButton.addActionListener { - Desktop.getDesktop().browse(URI("https://platform.openai.com/account/api-keys")) - } - formBuilder.addLabeledComponent("OpenAI Account", openAccountButton) - - val testButton = JXButton("Test Key") - testButton.addActionListener { - val apiKey = apiKeyInput.password.joinToString("") - try { - OpenAIClient( - key = mapOf( - APIProvider.OpenAI to apiKey - ) - ).listModels() - JOptionPane.showMessageDialog( - null, - "The API key was accepted by the server. The new value will be saved.", - "Success", - JOptionPane.INFORMATION_MESSAGE - ) - AppSettingsState.instance.apiKey = mapOf(APIProvider.OpenAI.name to apiKey).toMutableMap() - } catch (e: Exception) { - JOptionPane.showMessageDialog( - null, "The API key was rejected by the server.", "Failure", JOptionPane.WARNING_MESSAGE - ) - return@addActionListener - } - } - formBuilder.addLabeledComponent("Validation", testButton) - val showOptionDialog = showOptionDialog( - formBuilder.panel, "Dismiss", title = "Error", modal = true - ) - log.info("showOptionDialog = $showOptionDialog") - } else if (e.matches { ScriptException::class.java.isAssignableFrom(it.javaClass) }) { - val scriptException = e.get { ScriptException::class.java.isAssignableFrom(it.javaClass) } as ScriptException? + fun error(log: org.slf4j.Logger, msg: String, e: Throwable) { + log.error(msg, e) + errorLog += Pair(msg, e) + singleThreadPool.submit { + if (AppSettingsState.instance.suppressErrors) { + return@submit + } else if (e.matches { ModerationException::class.java.isAssignableFrom(it.javaClass) }) { + JOptionPane.showMessageDialog( + null, e.message, "This request was rejected by OpenAI Moderation", JOptionPane.WARNING_MESSAGE + ) + } else if (e.matches { + java.lang.InterruptedException::class.java.isAssignableFrom(it.javaClass) && it.message?.contains( + "sleep interrupted" + ) == true + }) { + JOptionPane.showMessageDialog( + null, + "This request was cancelled by the user", + "User Cancelled Request", + JOptionPane.WARNING_MESSAGE + ) + } else if (e.matches { IOException::class.java.isAssignableFrom(it.javaClass) && it.message?.contains("Incorrect API key") == true }) { + + val formBuilder = FormBuilder.createFormBuilder() + + formBuilder.addLabeledComponent( + "Error", JLabel("The API key was rejected by the server.") + ) + + val apiKeyInput = JBPasswordField() + //bugReportTextArea.rows = 40 + apiKeyInput.columns = 80 + apiKeyInput.isEditable = true + //apiKeyInput.text = """""".trimMargin() + formBuilder.addLabeledComponent("API Key", apiKeyInput) + + val openAccountButton = JXButton("Open Account Page") + openAccountButton.addActionListener { + Desktop.getDesktop().browse(URI("https://platform.openai.com/account/api-keys")) + } + formBuilder.addLabeledComponent("OpenAI Account", openAccountButton) + + val testButton = JXButton("Test Key") + testButton.addActionListener { + val apiKey = apiKeyInput.password.joinToString("") + try { + OpenAIClient( + key = mapOf( + APIProvider.OpenAI to apiKey + ) + ).listModels() + JOptionPane.showMessageDialog( + null, + "The API key was accepted by the server. The new value will be saved.", + "Success", + JOptionPane.INFORMATION_MESSAGE + ) + AppSettingsState.instance.apiKey = mapOf(APIProvider.OpenAI.name to apiKey).toMutableMap() + } catch (e: Exception) { + JOptionPane.showMessageDialog( + null, "The API key was rejected by the server.", "Failure", JOptionPane.WARNING_MESSAGE + ) + return@addActionListener + } + } + formBuilder.addLabeledComponent("Validation", testButton) + val showOptionDialog = showOptionDialog( + formBuilder.panel, "Dismiss", title = "Error", modal = true + ) + log.info("showOptionDialog = $showOptionDialog") + } else if (e.matches { ScriptException::class.java.isAssignableFrom(it.javaClass) }) { + val scriptException = + e.get { ScriptException::class.java.isAssignableFrom(it.javaClass) } as ScriptException? // val dynamicActionException = // e.get { ActionSettingsRegistry.DynamicActionException::class.java.isAssignableFrom(it.javaClass) } as ActionSettingsRegistry.DynamicActionException? - val formBuilder = FormBuilder.createFormBuilder() + val formBuilder = FormBuilder.createFormBuilder() - formBuilder.addLabeledComponent( - "Error", JLabel("An error occurred while executing the dynamic action.") - ) + formBuilder.addLabeledComponent( + "Error", JLabel("An error occurred while executing the dynamic action.") + ) - val bugReportTextArea = JBTextArea() - bugReportTextArea.rows = 40 - bugReportTextArea.columns = 80 - bugReportTextArea.isEditable = false - bugReportTextArea.text = """ + val bugReportTextArea = JBTextArea() + bugReportTextArea.rows = 40 + bugReportTextArea.columns = 80 + bugReportTextArea.isEditable = false + bugReportTextArea.text = """ |Script Error: ${scriptException?.message} | |Error Details: @@ -842,32 +846,32 @@ object UITools { |${toString(e)/*.indent(" ")*/} |``` |""".trimMargin() - formBuilder.addLabeledComponent("Error Report", wrapScrollPane(bugReportTextArea)) - - val supressFutureErrors = JCheckBox("Suppress Future Error Popups") - supressFutureErrors.isSelected = false - formBuilder.addComponent(supressFutureErrors) - - val showOptionDialog = showOptionDialog( - formBuilder.panel, "Dismiss", title = "Error", modal = true - ) - log.info("showOptionDialog = $showOptionDialog") - if (supressFutureErrors.isSelected) { - AppSettingsState.instance.suppressErrors = true - } - } else { - val formBuilder = FormBuilder.createFormBuilder() - - formBuilder.addLabeledComponent( - "Error", - JLabel("Oops! Something went wrong. An error report has been generated. You can copy and paste the report below into a new issue on our Github page.") - ) - - val bugReportTextArea = JBTextArea() - bugReportTextArea.rows = 40 - bugReportTextArea.columns = 80 - bugReportTextArea.isEditable = false - bugReportTextArea.text = """ + formBuilder.addLabeledComponent("Error Report", wrapScrollPane(bugReportTextArea)) + + val supressFutureErrors = JCheckBox("Suppress Future Error Popups") + supressFutureErrors.isSelected = false + formBuilder.addComponent(supressFutureErrors) + + val showOptionDialog = showOptionDialog( + formBuilder.panel, "Dismiss", title = "Error", modal = true + ) + log.info("showOptionDialog = $showOptionDialog") + if (supressFutureErrors.isSelected) { + AppSettingsState.instance.suppressErrors = true + } + } else { + val formBuilder = FormBuilder.createFormBuilder() + + formBuilder.addLabeledComponent( + "Error", + JLabel("Oops! Something went wrong. An error report has been generated. You can copy and paste the report below into a new issue on our Github page.") + ) + + val bugReportTextArea = JBTextArea() + bugReportTextArea.rows = 40 + bugReportTextArea.columns = 80 + bugReportTextArea.isEditable = false + bugReportTextArea.text = """ |Log Message: $msg |Error Message: ${e.message} |Error Type: ${e.javaClass.name} @@ -888,78 +892,78 @@ object UITools { |Error History: | |${ - errorLog.filter { it.second != e }.joinToString("\n") { - """ + errorLog.filter { it.second != e }.joinToString("\n") { + """ |${it.first} |``` |${toString(it.second)/*.indent(" ")*/} |``` |""".trimMargin() - } - } + } + } |""".trimMargin() - formBuilder.addLabeledComponent("System Report", wrapScrollPane(bugReportTextArea)) - - val openButton = JXButton("Open New Issue on our Github page") - openButton.addActionListener { - Desktop.getDesktop().browse(URI("https://github.com/SimiaCryptus/intellij-aicoder/issues/new")) + formBuilder.addLabeledComponent("System Report", wrapScrollPane(bugReportTextArea)) + + val openButton = JXButton("Open New Issue on our Github page") + openButton.addActionListener { + Desktop.getDesktop().browse(URI("https://github.com/SimiaCryptus/intellij-aicoder/issues/new")) + } + formBuilder.addLabeledComponent("Report Issue/Request Help", openButton) + + val supressFutureErrors = JCheckBox("Suppress Future Error Popups") + supressFutureErrors.isSelected = false + formBuilder.addComponent(supressFutureErrors) + + val showOptionDialog = showOptionDialog( + formBuilder.panel, "Dismiss", title = "Error", modal = true + ) + log.info("showOptionDialog = $showOptionDialog") + if (supressFutureErrors.isSelected) { + AppSettingsState.instance.suppressErrors = true + } + } } - formBuilder.addLabeledComponent("Report Issue/Request Help", openButton) + } - val supressFutureErrors = JCheckBox("Suppress Future Error Popups") - supressFutureErrors.isSelected = false - formBuilder.addComponent(supressFutureErrors) + private fun Throwable.matches(matchFn: (Throwable) -> Boolean): Boolean { + if (matchFn(this)) return true + if (this.cause != null && this.cause !== this) return this.cause!!.matches(matchFn) + return false + } - val showOptionDialog = showOptionDialog( - formBuilder.panel, "Dismiss", title = "Error", modal = true + fun Throwable.get(matchFn: (Throwable) -> Boolean): Throwable? { + if (matchFn(this)) return this + if (this.cause != null && this.cause !== this) return this.cause!!.get(matchFn) + return null + } + + fun toString(e: Throwable): String { + val sw = StringWriter() + val pw = PrintWriter(sw) + e.printStackTrace(pw) + return sw.toString() + } + + fun showInputDialog( + parentComponent: Component?, message: Any?, title: String?, messageType: Int + ): Any? { + val icon = null + val selectionValues = null + val initialSelectionValue = null + val pane = JOptionPane( + message, messageType, JOptionPane.OK_CANCEL_OPTION, icon, null, null ) - log.info("showOptionDialog = $showOptionDialog") - if (supressFutureErrors.isSelected) { - AppSettingsState.instance.suppressErrors = true - } - } - } - } - - private fun Throwable.matches(matchFn: (Throwable) -> Boolean): Boolean { - if (matchFn(this)) return true - if (this.cause != null && this.cause !== this) return this.cause!!.matches(matchFn) - return false - } - - fun Throwable.get(matchFn: (Throwable) -> Boolean): Throwable? { - if (matchFn(this)) return this - if (this.cause != null && this.cause !== this) return this.cause!!.get(matchFn) - return null - } - - fun toString(e: Throwable): String { - val sw = StringWriter() - val pw = PrintWriter(sw) - e.printStackTrace(pw) - return sw.toString() - } - - fun showInputDialog( - parentComponent: Component?, message: Any?, title: String?, messageType: Int - ): Any? { - val icon = null - val selectionValues = null - val initialSelectionValue = null - val pane = JOptionPane( - message, messageType, JOptionPane.OK_CANCEL_OPTION, icon, null, null - ) - pane.wantsInput = true - pane.selectionValues = selectionValues - pane.initialSelectionValue = initialSelectionValue - //pane.isComponentOrientationLeftToRight = true - val dialog = pane.createDialog(parentComponent, title) - pane.selectInitialValue() - dialog.show() - dialog.dispose() - val value = pane.inputValue - return if (value == JOptionPane.UNINITIALIZED_VALUE) null else value - } + pane.wantsInput = true + pane.selectionValues = selectionValues + pane.initialSelectionValue = initialSelectionValue + //pane.isComponentOrientationLeftToRight = true + val dialog = pane.createDialog(parentComponent, title) + pane.selectInitialValue() + dialog.show() + dialog.dispose() + val value = pane.inputValue + return if (value == JOptionPane.UNINITIALIZED_VALUE) null else value + } } diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiClassContext.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiClassContext.kt index 04c9a25e..2935a5a5 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiClassContext.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiClassContext.kt @@ -5,7 +5,12 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiFile -class PsiClassContext(val text: String, private val isPrior: Boolean, private val isOverlap: Boolean, val language: ComputerLanguage) { +class PsiClassContext( + val text: String, + private val isPrior: Boolean, + private val isOverlap: Boolean, + val language: ComputerLanguage +) { val children = ArrayList() /** diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiUtil.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiUtil.kt index a3c301aa..26882580 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiUtil.kt +++ b/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiUtil.kt @@ -21,6 +21,7 @@ object PsiUtil { "CssBlock", "FunctionDefinition" ) + @JvmStatic val ELEMENTS_COMMENTS = arrayOf( "Comment" diff --git a/src/main/kotlin/icons/MyIcons.kt b/src/main/kotlin/icons/MyIcons.kt new file mode 100644 index 00000000..ce754fd4 --- /dev/null +++ b/src/main/kotlin/icons/MyIcons.kt @@ -0,0 +1,14 @@ +package icons + +import com.intellij.openapi.util.IconLoader + +object MyIcons { + + @JvmField val icon = IconLoader.getIcon("/META-INF/toolbarIcon.svg", javaClass) + /* + IconLoader.findIcon( + url = classLoader.getResource("./META-INF/toolbarIcon.svg"), + storeToCache = true + ) + */ +} \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 99b26b7e..bf3b5921 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -5,10 +5,6 @@ AI-Powered com.intellij.modules.platform com.intellij.modules.lang - @@ -17,11 +13,8 @@ instance="com.github.simiacryptus.aicoder.config.StaticAppSettingsConfigurable" id="org.intellij.sdk.settings.AppSettingsConfigurable" displayName="AI Coder"/> - - + + + + - + - + - + - + - + - + - - - - - - -