summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--continuedev/src/continuedev/core/config.py10
-rw-r--r--continuedev/src/continuedev/core/main.py11
-rw-r--r--continuedev/src/continuedev/plugins/context_providers/file_context_provider.py5
-rw-r--r--extension/react-app/src/components/ComboBox.tsx23
-rw-r--r--extension/react-app/src/components/PillButton.tsx23
-rw-r--r--extension/react-app/src/pages/gui.tsx40
6 files changed, 80 insertions, 32 deletions
diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py
index bb9ca323..565c617d 100644
--- a/continuedev/src/continuedev/core/config.py
+++ b/continuedev/src/continuedev/core/config.py
@@ -56,11 +56,11 @@ class ContinueConfig(BaseModel):
# Want to force these to be the slash commands for now
@validator('slash_commands', pre=True)
def default_slash_commands_validator(cls, v):
- from ..steps.open_config import OpenConfigStep
- from ..steps.clear_history import ClearHistoryStep
- from ..steps.feedback import FeedbackStep
- from ..steps.comment_code import CommentCodeStep
- from ..steps.main import EditHighlightedCodeStep
+ from ..plugins.steps.open_config import OpenConfigStep
+ from ..plugins.steps.clear_history import ClearHistoryStep
+ from ..plugins.steps.feedback import FeedbackStep
+ from ..plugins.steps.comment_code import CommentCodeStep
+ from ..plugins.steps.main import EditHighlightedCodeStep
DEFAULT_SLASH_COMMANDS = [
SlashCommand(
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 6c6adccc..df9b98ef 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -207,12 +207,21 @@ class ContextItemId(BaseModel):
provider_title: str
item_id: str
+ @validator('provider_title', 'item_id')
+ def must_be_valid_id(cls, v):
+ import re
+ if not re.match(r'^[0-9a-zA-Z_-]*$', v):
+ raise ValueError(
+ "Both provider_title and item_id can only include characters 0-9, a-z, A-Z, -, and _")
+ return v
+
def to_string(self) -> str:
return f"{self.provider_title}-{self.item_id}"
@staticmethod
def from_string(string: str) -> 'ContextItemId':
- provider_title, item_id = string.split('-')
+ provider_title, *rest = string.split('-')
+ item_id = '-'.join(rest)
return ContextItemId(provider_title=provider_title, item_id=item_id)
diff --git a/continuedev/src/continuedev/plugins/context_providers/file_context_provider.py b/continuedev/src/continuedev/plugins/context_providers/file_context_provider.py
index 854310b1..632a876c 100644
--- a/continuedev/src/continuedev/plugins/context_providers/file_context_provider.py
+++ b/continuedev/src/continuedev/plugins/context_providers/file_context_provider.py
@@ -1,4 +1,5 @@
import os
+import re
from typing import List
from ...core.main import ContextItem, ContextItemDescription, ContextItemId
from ...core.context import ContextProvider
@@ -45,11 +46,11 @@ class FileContextProvider(ContextProvider):
content=get_file_contents(file)[:min(
2000, len(get_file_contents(file)))],
description=ContextItemDescription(
- name=f"File {os.path.basename(file)}",
+ name=os.path.basename(file),
description=file,
id=ContextItemId(
provider_title=self.title,
- item_id=file
+ item_id=re.sub(r'[^0-9a-zA-Z_-]', '', file)
)
)
) for file in filepaths]
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index fdd1e9b7..7d266c6e 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -20,6 +20,8 @@ import { ContextItem } from "../../../schema/FullState";
import { postVscMessage } from "../vscode";
import { GUIClientContext } from "../App";
import { MeiliSearch } from "meilisearch";
+import { setBottomMessageCloseTimeout } from "../redux/slices/uiStateSlice";
+import { useDispatch } from "react-redux";
const SEARCH_INDEX_NAME = "continue_context_items";
@@ -124,6 +126,7 @@ interface ComboBoxProps {
const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
const searchClient = new MeiliSearch({ host: "http://127.0.0.1:7700" });
const client = useContext(GUIClientContext);
+ const dispatch = useDispatch();
const [history, setHistory] = React.useState<string[]>([]);
// The position of the current command you are typing now, so the one that will be appended to history once you press enter
@@ -179,8 +182,8 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
})
);
})
- .catch((err) => {
- console.error(err);
+ .catch(() => {
+ // Swallow errors, because this simply is not supported on Windows at the moment
});
return;
}
@@ -202,6 +205,12 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
}
}, [downshiftProps.inputValue]);
+ const divRef = React.useRef<HTMLDivElement>(null);
+ const ulRef = React.useRef<HTMLUListElement>(null);
+ const showAbove = () => {
+ return (divRef.current?.getBoundingClientRect().top || 0) > UlMaxHeight;
+ };
+
useImperativeHandle(ref, () => downshiftProps, [downshiftProps]);
const [metaKeyPressed, setMetaKeyPressed] = useState(false);
@@ -241,12 +250,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
};
}, [inputRef.current]);
- const divRef = React.useRef<HTMLDivElement>(null);
- const ulRef = React.useRef<HTMLUListElement>(null);
- const showAbove = () => {
- return (divRef.current?.getBoundingClientRect().top || 0) > UlMaxHeight;
- };
-
return (
<>
<div className="px-2 flex gap-2 items-center flex-wrap mt-2">
@@ -304,6 +307,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
},
onFocus: (e) => {
setFocused(true);
+ dispatch(setBottomMessageCloseTimeout(undefined));
},
onBlur: (e) => {
setFocused(false);
@@ -358,6 +362,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
setCurrentlyInContextQuery(false);
}
},
+ onClick: () => {
+ dispatch(setBottomMessageCloseTimeout(undefined));
+ },
ref: inputRef,
})}
/>
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index af4263af..660ede09 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -1,8 +1,9 @@
-import { useContext, useEffect, useState } from "react";
+import { useContext, useEffect, useRef, useState } from "react";
import styled from "styled-components";
import {
StyledTooltip,
defaultBorderRadius,
+ lightGray,
secondaryDark,
vscBackground,
vscForeground,
@@ -96,12 +97,19 @@ const PillButton = (props: PillButtonProps) => {
<>
<b>{props.item.description.name}</b>:{" "}
{props.item.description.description}
- <StyledMarkdownPreview
- source={`\`\`\`\n${props.item.content}\n\`\`\``}
- wrapperElement={{
- "data-color-mode": "dark",
- }}
- />
+ <pre>
+ <code
+ style={{
+ fontSize: "10px",
+ backgroundColor: vscBackground,
+ color: vscForeground,
+ whiteSpace: "pre-wrap",
+ wordWrap: "break-word",
+ }}
+ >
+ {props.item.content}
+ </code>
+ </pre>
</>
)
);
@@ -178,6 +186,7 @@ const PillButton = (props: PillButtonProps) => {
backgroundColor={"#cc000055"}
onClick={() => {
client?.deleteContextWithIds([props.item.description.id]);
+ dispatch(setBottomMessageCloseTimeout(undefined));
}}
>
<Trash style={{ margin: "auto" }} width="1.6em"></Trash>
diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx
index 9a00802b..03b24349 100644
--- a/extension/react-app/src/pages/gui.tsx
+++ b/extension/react-app/src/pages/gui.tsx
@@ -125,6 +125,24 @@ function GUI(props: GUIProps) {
(state: RootStore) => state.uiState.bottomMessage
);
+ const [displayBottomMessageOnBottom, setDisplayBottomMessageOnBottom] =
+ useState<boolean>(true);
+ const mainTextInputRef = useRef<HTMLInputElement>(null);
+
+ const aboveComboBoxDivRef = useRef<HTMLDivElement>(null);
+
+ useEffect(() => {
+ if (!aboveComboBoxDivRef.current) return;
+ if (
+ aboveComboBoxDivRef.current.getBoundingClientRect().top >
+ window.innerHeight / 2
+ ) {
+ setDisplayBottomMessageOnBottom(false);
+ } else {
+ setDisplayBottomMessageOnBottom(true);
+ }
+ }, [bottomMessage, aboveComboBoxDivRef.current]);
+
const topGuiDivRef = useRef<HTMLDivElement>(null);
const [scrollTimeout, setScrollTimeout] = useState<NodeJS.Timeout | null>(
@@ -156,6 +174,8 @@ function GUI(props: GUIProps) {
history.timeline[history.current_index]?.active
) {
client?.deleteAtIndex(history.current_index);
+ } else if (e.key === "Escape") {
+ dispatch(setBottomMessageCloseTimeout(undefined));
}
};
window.addEventListener("keydown", listener);
@@ -182,7 +202,6 @@ function GUI(props: GUIProps) {
setWaitingForSteps(waitingForSteps);
setHistory(state.history);
- console.log((state as any).selected_context_items);
setSelectedContextItems(state.selected_context_items);
setUserInputQueue(state.user_input_queue);
setAddingHighlightedCode(state.adding_highlighted_code);
@@ -216,8 +235,6 @@ function GUI(props: GUIProps) {
scrollToBottom();
}, [waitingForSteps]);
- const mainTextInputRef = useRef<HTMLInputElement>(null);
-
const onMainTextInput = (event?: any) => {
if (mainTextInputRef.current) {
let input = (mainTextInputRef.current as any).inputValue;
@@ -349,6 +366,7 @@ function GUI(props: GUIProps) {
})}
</div>
+ <div ref={aboveComboBoxDivRef} />
<ComboBox
ref={mainTextInputRef}
onEnter={(e) => {
@@ -370,21 +388,25 @@ function GUI(props: GUIProps) {
onMouseEnter={() => {
dispatch(setBottomMessageCloseTimeout(undefined));
}}
- onMouseLeave={() => {
- dispatch(setBottomMessage(undefined));
+ onMouseLeave={(e) => {
+ if (!e.buttons) {
+ dispatch(setBottomMessage(undefined));
+ }
}}
style={{
position: "fixed",
- bottom: "50px",
+ bottom: displayBottomMessageOnBottom ? "50px" : undefined,
+ top: displayBottomMessageOnBottom ? undefined : "50px",
left: "0",
right: "0",
- margin: "16px",
+ margin: "8px",
+ marginTop: "0px",
backgroundColor: vscBackground,
color: vscForeground,
borderRadius: defaultBorderRadius,
- padding: "16px",
+ padding: "12px",
zIndex: 100,
- boxShadow: `0px 0px 10px 0px ${vscForeground}`,
+ boxShadow: `0px 0px 6px 0px ${vscForeground}`,
maxHeight: "50vh",
overflow: "scroll",
}}