Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Generate corrected terminal commands using assistant #346

Merged
merged 2 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "biscuit"
version = "2.95.0"
version = "2.96.0"
description = "The uncompromising code editor"
authors = ["Billy <billydevbusiness@gmail.com>"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion src/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "2.95.0"
__version__ = "2.96.0"
__version_info__ = tuple([int(num) for num in __version__.split(".")])

import sys
Expand Down
8 changes: 4 additions & 4 deletions src/biscuit/common/actionset.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def __init__(
self,
description: str,
prefix: str,
items: List[Tuple[str, Callable]] = [],
pinned: List[Tuple[str, Callable[[str], None]]] = [],
items: List[List[str | Callable]] = [],
pinned: List[List[str | Callable[[str], None]]] = [],
*args,
**kwargs
) -> None:
Expand All @@ -25,8 +25,8 @@ def __init__(
Args:
description (str): The description of the actionset.
prefix (str): The prefix of the actionset.
items (List[Tuple[str, Callable]], optional): The list of actions. Defaults to [].
pinned (List[Tuple[str, Callable[[str], None]]], optional): The list of pinned actions. Defaults to [].
items (List[Tuple[str | Callable]], optional): The list of actions. Defaults to [].
pinned (List[List[str | Callable[[str], None]]], optional): The list of pinned actions. Defaults to [].
"""

super().__init__(items, *args, **kwargs)
Expand Down
36 changes: 18 additions & 18 deletions src/biscuit/layout/drawer/drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def github(self) -> GitHub:
def extensions(self) -> Extensions:
return self.default_views["Extensions"]

def show_view(self, view: NavigationDrawerView) -> None:
def show_view(self, view: NavigationDrawerView) -> NavigationDrawerView:
"""Show a view in the drawer.

Args:
Expand All @@ -130,31 +130,31 @@ def show_view(self, view: NavigationDrawerView) -> None:
if i.view == view:
self.activitybar.set_active_slot(i)
i.enable()
break
return view

def show_explorer(self) -> None:
self.show_view(self.explorer)
def show_explorer(self) -> Explorer:
return self.show_view(self.explorer)

def show_outline(self) -> None:
self.show_view(self.outline)
def show_outline(self) -> Outline:
return self.show_view(self.outline)

def show_search(self) -> None:
self.show_view(self.search)
def show_search(self) -> Search:
return self.show_view(self.search)

def show_source_control(self) -> None:
self.show_view(self.source_control)
def show_source_control(self) -> SourceControl:
return self.show_view(self.source_control)

def show_debug(self) -> None:
self.show_view(self.debug)
def show_debug(self) -> Debug:
return self.show_view(self.debug)

def show_ai(self) -> None:
self.show_view(self.ai)
def show_ai(self) -> AI:
return self.show_view(self.ai)

def show_github(self) -> None:
self.show_view(self.github)
def show_github(self) -> GitHub:
return self.show_view(self.github)

def show_extensions(self) -> None:
self.show_view(self.extensions)
def show_extensions(self) -> Extensions:
return self.show_view(self.extensions)

def pack(self):
super().pack(side=tk.LEFT, fill=tk.Y)
20 changes: 10 additions & 10 deletions src/biscuit/layout/panel/panelbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,40 +33,40 @@ def __init__(self, master: Panel, *args, **kwargs) -> None:
self.active_tabs: list[Tab] = []
self.active_tab = None

self.buttons: list[IconButton] = []
self.actions: list[IconButton] = []

# These buttons are common for all panel views
self.default_buttons = (
self.default_actions = (
("close", content.toggle_panel),
("chevron-up", content.toggle_max_panel, "chevron-down"),
)

for button in self.default_buttons:
for button in self.default_actions:
IconButton(self, *button).pack(side=tk.RIGHT)

def add_buttons(self, buttons: list[IconButton]) -> None:
def add_actions(self, buttons: list[IconButton]) -> None:
"""Add the buttons to the control buttons

Args:
buttons (list[IconButton]): buttons to be added"""

for button in buttons:
button.pack(side=tk.LEFT)
self.buttons.append(button)
self.actions.append(button)

def replace_buttons(self, buttons: list[IconButton]) -> None:
def replace_actions(self, buttons: list[IconButton]) -> None:
"""Replace the control buttons with the new buttons

Args:
buttons (list[IconButton]): new buttons"""

self.clear()
self.add_buttons(buttons)
self.add_actions(buttons)

def clear(self) -> None:
for button in self.buttons:
for button in self.actions:
button.pack_forget()
self.buttons.clear()
self.actions.clear()

def add_tab(self, view: PanelView) -> None:
"""Add the view to the tabs
Expand All @@ -87,7 +87,7 @@ def set_active_tab(self, selected_tab: Tab) -> None:
selected_tab (Tab): selected tab"""

self.active_tab = selected_tab
self.replace_buttons(selected_tab.view.__actions__)
self.replace_actions(selected_tab.view.__actions__)
for tab in self.active_tabs:
if tab != selected_tab:
tab.deselect()
2 changes: 1 addition & 1 deletion src/biscuit/views/ai/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class AI(NavigationDrawerView):
- The chat can be refreshed to start a new chat."""

def __init__(self, master, *args, **kwargs) -> None:
self.__buttons__ = [
self.__actions__ = [
("refresh", self.new_chat),
]
super().__init__(master, *args, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/debug/callstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class CallStack(NavigationDrawerViewItem):

def __init__(self, master, *args, **kwargs) -> None:
self.title = "Callstack"
self.__buttons__ = ()
self.__actions__ = ()
super().__init__(master, itembar=True, *args, **kwargs)

self.tree = Tree(self.content, cursor="hand2")
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/debug/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Debug(NavigationDrawerView):
- Debugger run controls are displayed in the editor toolbar."""

def __init__(self, master, *args, **kwargs) -> None:
self.__buttons__ = []
self.__actions__ = []
super().__init__(master, *args, **kwargs)
self.__icon__ = "bug"
self.name = "Debug"
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/debug/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Variables(NavigationDrawerViewItem):

def __init__(self, master, *args, **kwargs) -> None:
self.title = "Variables"
self.__buttons__ = ()
self.__actions__ = ()
super().__init__(master, itembar=True, *args, **kwargs)

self.tree = Tree(self.content, *args, **kwargs)
Expand Down
8 changes: 6 additions & 2 deletions src/biscuit/views/drawer_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class NavigationDrawerViewItem(Frame):
- Contains the itembar and the content of the item.
"""

__buttons__ = []
__actions__ = []
title = "Item"

def __init__(
Expand All @@ -38,7 +38,7 @@ def __init__(

if itembar:
self.itembar = NavigationDrawerItemToolBar(
self, self.title, self.__buttons__
self, self.title, self.__actions__
)
self.itembar.grid(row=0, column=0, sticky=tk.NSEW)

Expand All @@ -48,6 +48,10 @@ def __init__(
self.content.grid_columnconfigure(0, weight=1)
self.content.grid(row=1 if itembar else 0, column=0, sticky=tk.NSEW)

def add_action(self, icon: str, event) -> None:
if self.itembar_enabled:
self.itembar.add_action(icon, event)

def set_title(self, title: str) -> None:
if self.itembar_enabled:
self.itembar.set_title(title)
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/explorer/directorytree.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __init__(
**kwargs,
) -> None:
self.title = "No folder opened"
self.__buttons__ = (
self.__actions__ = (
("new-file", lambda: self.base.palette.show("newfile:")),
("new-folder", lambda: self.base.palette.show("newfolder:")),
("refresh", self.refresh_root),
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/explorer/explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Explorer(NavigationDrawerView):
"""

def __init__(self, master, *args, **kwargs) -> None:
self.__buttons__ = []
self.__actions__ = []
super().__init__(master, *args, **kwargs)
self.__icon__ = "files"
self.name = "Explorer"
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/explorer/open_editors.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class OpenEditors(NavigationDrawerViewItem):

def __init__(self, master, startpath=None, itembar=True, *args, **kwargs) -> None:
self.title = "Open Editors"
self.__buttons__ = (("new-file", lambda: self.base.palette.show("newfile:")),)
self.__actions__ = (("new-file", lambda: self.base.palette.show("newfile:")),)
super().__init__(master, itembar=itembar, *args, **kwargs)
self.path = startpath
self.nodes = {}
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/extensions/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Results(NavigationDrawerViewItem):
fetching: threading.Event

def __init__(self, master, *args, **kwargs) -> None:
self.__buttons__ = ()
self.__actions__ = ()
self.title = "Available"

super().__init__(master, *args, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/github/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class GitHub(NavigationDrawerView):
"""

def __init__(self, master, *args, **kwargs) -> None:
self.__buttons__ = [("refresh", self.on_directory_change)]
self.__actions__ = [("refresh", self.on_directory_change)]
super().__init__(master, *args, **kwargs)
self.__icon__ = "github"
self.name = "GitHub"
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/github/issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Issues(NavigationDrawerViewItem):

def __init__(self, master, itembar=True, *args, **kwargs) -> None:
self.title = "Open Issues"
self.__buttons__ = ()
self.__actions__ = ()
super().__init__(master, itembar=itembar, *args, **kwargs)

self.url_template = "https://api.github.com/repos/{}/{}/issues"
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/github/prs.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class PRs(NavigationDrawerViewItem):

def __init__(self, master, itembar=True, *args, **kwargs) -> None:
self.title = "Pull Requests"
self.__buttons__ = ()
self.__actions__ = ()
super().__init__(master, itembar=itembar, *args, **kwargs)

self.url_template = "https://api.github.com/repos/{}/{}/pulls"
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/logs/logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Logs(PanelView):

def __init__(self, master, *args, **kwargs) -> None:
super().__init__(master, *args, **kwargs)
self.__buttons__ = (("clear-all",),)
self.__actions__ = (("clear-all",),)

self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/outline/outline.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Outline(NavigationDrawerView):
"""

def __init__(self, master, *args, **kwargs) -> None:
self.__buttons__ = [
self.__actions__ = [
("refresh",),
("collapse-all",),
("ellipsis",),
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/problems/problems.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Problems(PanelView):

def __init__(self, master, *args, **kwargs) -> None:
super().__init__(master, *args, **kwargs)
self.__buttons__ = (("clear-all", self.clear),)
self.__actions__ = (("clear-all", self.clear),)

self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/search/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Search(NavigationDrawerView):
"""

def __init__(self, master, *args, **kwargs) -> None:
self.__buttons__ = (("refresh",), ("clear-all",), ("collapse-all",))
self.__actions__ = (("refresh",), ("clear-all",), ("collapse-all",))
super().__init__(master, *args, **kwargs)
self.__icon__ = "search"
self.name = "Search"
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/sourcecontrol/changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Changes(NavigationDrawerViewItem):
"""

def __init__(self, master, *args, **kwargs) -> None:
self.__buttons__ = (
self.__actions__ = (
("discard", self.git_discard_all),
("add", self.git_add_all),
)
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/views/sourcecontrol/stagedchanges.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class StagedChanges(NavigationDrawerViewItem):
"""

def __init__(self, master, *args, **kwargs) -> None:
self.__buttons__ = (("remove", self.git_remove_all),)
self.__actions__ = (("remove", self.git_remove_all),)
self.title = "Staged Changes"
super().__init__(master, *args, **kwargs)
self.config(**self.base.theme.views.sidebar.item)
Expand Down
48 changes: 48 additions & 0 deletions src/biscuit/views/terminal/ai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from __future__ import annotations

import typing

import google.generativeai as ai
from google.generativeai.types import HarmBlockThreshold, HarmCategory

if typing.TYPE_CHECKING:
from .terminalbase import TerminalBase


class AI:
def __init__(self, terminal: TerminalBase) -> None:
self.terminal = terminal
self.base = terminal.base

self.prompt = f"""You are an expert at terminal commands. you know all the commands
and their arguments. You can generate correct commands with arguments from the command
that was not recognized by the terminal. You can recognize and fix commands from any shell
in any operating system. Only return the fixed command, and dont explain it.

The user may talk in english as well, its when he is not sure how to write the command.
You can also generate commands for the user if he is not sure what to do!

Shell executable used: {self.terminal.shell}
Shell name: {self.terminal.name}
System details: {str(self.base.system)}
Input from user: """

self.model = ai.GenerativeModel(
"gemini-1.5-flash",
safety_settings={
HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
},
)
self.chat = self.model.start_chat()

def get_gemini_response(self, err_command: str) -> str:
try:
response = self.chat.send_message([self.prompt, err_command])
if response and response.text:
self.base.palette.show("runc:", response.text.strip())
except Exception as e:
self.base.logger.error(e)
self.base.drawer.show_ai().add_placeholder()
Loading
Loading