mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
selection
This commit is contained in:
parent
6298be394d
commit
9cf4980004
4 changed files with 126 additions and 19 deletions
|
|
@ -9,6 +9,66 @@ import { atomOneDarkReasonable } from "react-syntax-highlighter/dist/esm/styles/
|
|||
import { VoidCodeEditor } from '../util/inputs.js';
|
||||
|
||||
|
||||
|
||||
export function getLanguageFromFileName(fileName: string): string {
|
||||
if (!fileName) return 'plaintext';
|
||||
|
||||
const ext = fileName.toLowerCase().split('.').pop();
|
||||
if (!ext) return 'plaintext';
|
||||
|
||||
const extensionMap: { [key: string]: string } = {
|
||||
// Web
|
||||
'html': 'html',
|
||||
'htm': 'html',
|
||||
'css': 'css',
|
||||
'scss': 'scss',
|
||||
'less': 'less',
|
||||
'js': 'javascript',
|
||||
'jsx': 'javascript',
|
||||
'ts': 'typescript',
|
||||
'tsx': 'typescript',
|
||||
'json': 'json',
|
||||
'jsonc': 'json',
|
||||
|
||||
// Programming Languages
|
||||
'py': 'python',
|
||||
'java': 'java',
|
||||
'cpp': 'cpp',
|
||||
'cc': 'cpp',
|
||||
'h': 'cpp',
|
||||
'hpp': 'cpp',
|
||||
'cs': 'csharp',
|
||||
'go': 'go',
|
||||
'rs': 'rust',
|
||||
'rb': 'ruby',
|
||||
'php': 'php',
|
||||
'sh': 'shell',
|
||||
'bash': 'shell',
|
||||
'zsh': 'shell',
|
||||
|
||||
// Markup/Config
|
||||
'md': 'markdown',
|
||||
'markdown': 'markdown',
|
||||
'xml': 'xml',
|
||||
'svg': 'xml',
|
||||
'yaml': 'yaml',
|
||||
'yml': 'yaml',
|
||||
'ini': 'ini',
|
||||
'toml': 'ini',
|
||||
|
||||
// Other
|
||||
'sql': 'sql',
|
||||
'graphql': 'graphql',
|
||||
'gql': 'graphql',
|
||||
'dockerfile': 'dockerfile',
|
||||
'docker': 'dockerfile'
|
||||
};
|
||||
|
||||
return extensionMap[ext] || 'plaintext';
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const BlockCode = ({ text, buttonsOnHover, language }: { text: string, buttonsOnHover?: ReactNode, language?: string }) => {
|
||||
|
||||
const customStyle = {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import React, { ButtonHTMLAttributes, FormEvent, FormHTMLAttributes, Fragment, u
|
|||
import { useAccessor, useThreadsState } from '../util/services.js';
|
||||
import { ChatMessage, CodeSelection, CodeStagingSelection, IThreadHistoryService } from '../../../threadHistoryService.js';
|
||||
|
||||
import { BlockCode } from '../markdown/BlockCode.js';
|
||||
import { BlockCode, getLanguageFromFileName } from '../markdown/BlockCode.js';
|
||||
import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js';
|
||||
import { URI } from '../../../../../../../base/common/uri.js';
|
||||
import { EndOfLinePreference } from '../../../../../../../editor/common/model.js';
|
||||
|
|
@ -86,6 +86,29 @@ const IconSquare = ({ size, className = '' }: { size: number, className?: string
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
export const IconWarning = ({ size, className = '' }: { size: number, className?: string }) => {
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
strokeWidth="0"
|
||||
viewBox="0 0 24 24"
|
||||
width={size}
|
||||
height={size}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
{/* Warning triangle */}
|
||||
<path d="M12 3L2 21h20L12 3zm0 3.3L19.3 19H4.7L12 6.3z" />
|
||||
|
||||
{/* Exclamation mark */}
|
||||
<rect x="11" y="10" width="2" height="6" />
|
||||
<circle cx="12" cy="18" r="1" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement>
|
||||
export const ButtonSubmit = ({ className, disabled, ...props }: ButtonProps & Required<Pick<ButtonProps, 'disabled'>>) => {
|
||||
return <button
|
||||
|
|
@ -109,7 +132,7 @@ export const ButtonStop = ({ className, ...props }: ButtonHTMLAttributes<HTMLBut
|
|||
type='button'
|
||||
{...props}
|
||||
>
|
||||
<IconSquare size={16} className="stroke-[2]" />
|
||||
<IconSquare size={10} className="stroke-[2]" />
|
||||
</button>
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +215,7 @@ export const SelectedFiles = (
|
|||
>
|
||||
{selections.map((selection, i) => {
|
||||
|
||||
const showSelectionText = selection.selectionStr && selectionIsOpened[i]
|
||||
const showSelectionText = !!(selection.selectionStr && selectionIsOpened[i])
|
||||
|
||||
return (
|
||||
<div key={i} // container for `selectionSummary` and `selectionText`
|
||||
|
|
@ -201,9 +224,11 @@ export const SelectedFiles = (
|
|||
{/* selection summary */}
|
||||
<div
|
||||
// className="relative rounded rounded-e-2xl flex items-center space-x-2 mx-1 mb-1 disabled:cursor-default"
|
||||
className={`grid grid-rows-2 gap-1 relative
|
||||
className={`grid grid-rows-2 gap-1 relative p-1
|
||||
select-none
|
||||
bg-vscode-badge-bg border border-vscode-button-border rounded-md
|
||||
bg-vscode-editor-bg hover:brightness-90
|
||||
border border-vscode-button-border rounded-md
|
||||
text-vscode-commandcenter-inactive-fg
|
||||
w-fit h-fit min-w-[81px] p-1
|
||||
`}
|
||||
onClick={() => {
|
||||
|
|
@ -222,7 +247,7 @@ export const SelectedFiles = (
|
|||
</span>
|
||||
|
||||
{/* type of selection */}
|
||||
<span className='truncate text-opacity-75'>{selection.selectionStr !== null ? 'Selection' : 'File'}</span>
|
||||
<span className='truncate'>{selection.selectionStr !== null ? 'Selection' : 'File'}</span>
|
||||
|
||||
{/* X button */}
|
||||
{type === 'staging' && // hoveredIdx === i
|
||||
|
|
@ -241,7 +266,7 @@ export const SelectedFiles = (
|
|||
{/* selection text */}
|
||||
{showSelectionText &&
|
||||
<div className='w-full'>
|
||||
<BlockCode text={selection.selectionStr!} />
|
||||
<BlockCode text={selection.selectionStr!} language={getLanguageFromFileName(selection.fileURI.path)} />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -286,6 +286,9 @@ const normalizeIndentation = (code: string): string => {
|
|||
}
|
||||
|
||||
export const VoidCodeEditor = ({ initValue, language }: { initValue: string, language: string | undefined }) => {
|
||||
|
||||
const MAX_HEIGHT = 200;
|
||||
|
||||
const divRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
const accessor = useAccessor()
|
||||
|
|
@ -302,10 +305,11 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan
|
|||
container,
|
||||
{
|
||||
automaticLayout: true,
|
||||
wordWrap: 'on',
|
||||
wordWrap: 'off',
|
||||
scrollbar: {
|
||||
vertical: 'hidden',
|
||||
vertical: 'auto',
|
||||
horizontal: 'auto',
|
||||
alwaysConsumeMouseWheel: false
|
||||
},
|
||||
lineNumbers: 'off',
|
||||
folding: false,
|
||||
|
|
@ -326,26 +330,35 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan
|
|||
}
|
||||
|
||||
onCreateInstance={useCallback((editor: CodeEditorWidget) => {
|
||||
|
||||
const model = modelService.createModel(initValue, null)
|
||||
editor.setModel(model);
|
||||
model.setLanguage(language ?? 'plaintext')
|
||||
|
||||
const container = editor.getDomNode()
|
||||
const parentNode = container?.parentElement
|
||||
if (parentNode)
|
||||
parentNode.style.height = `${editor.getScrollHeight() + 1}px` // the +1 is if there's a half pixel issue
|
||||
if (parentNode) {
|
||||
const height = Math.min(editor.getScrollHeight() + 1, MAX_HEIGHT);
|
||||
parentNode.style.height = `${height}px`;
|
||||
editor.layout();
|
||||
}
|
||||
|
||||
return []
|
||||
// Listen for content changes and update height
|
||||
const disposable = editor.onDidContentSizeChange(() => {
|
||||
if (parentNode) {
|
||||
const height = Math.min(editor.getScrollHeight() + 1, MAX_HEIGHT);
|
||||
parentNode.style.height = `${height}px`;
|
||||
editor.layout();
|
||||
}
|
||||
});
|
||||
|
||||
return [disposable]
|
||||
}, [modelService, initValue, language])}
|
||||
|
||||
dispose={useCallback((editor: CodeEditorWidget) => {
|
||||
editor.dispose();
|
||||
}, [])}
|
||||
|
||||
// ignored
|
||||
propsFn={useCallback(() => { return [] }, [])}
|
||||
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { FeatureName, featureNames, ModelSelection, modelSelectionsEqual, Provid
|
|||
import { useSettingsState, useRefreshModelState, useAccessor } from '../util/services.js'
|
||||
import { VoidSelectBox } from '../util/inputs.js'
|
||||
import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js'
|
||||
import { IconWarning } from '../sidebar-tsx/SidebarChat.js'
|
||||
|
||||
|
||||
const ModelSelectBox = ({ featureName }: { featureName: FeatureName }) => {
|
||||
|
|
@ -42,10 +43,18 @@ const ModelSelectBox = ({ featureName }: { featureName: FeatureName }) => {
|
|||
}
|
||||
|
||||
const DummySelectBox = () => {
|
||||
return <VoidSelectBox
|
||||
options={[{ text: 'Please add a model!', value: null }]}
|
||||
onChangeSelection={() => { }}
|
||||
/>
|
||||
|
||||
return <div>
|
||||
<IconWarning
|
||||
size={24}
|
||||
className='text-orange-900'
|
||||
/>
|
||||
<span className='text-orange-900'>Add a model</span>
|
||||
</div>
|
||||
// return <VoidSelectBox
|
||||
// options={[{ text: 'Please add a model!', value: null }]}
|
||||
// onChangeSelection={() => { }}
|
||||
// />
|
||||
}
|
||||
|
||||
export const ModelDropdown = ({ featureName }: { featureName: FeatureName }) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue