Skip to content

Commit

Permalink
Merge branch 'main' into cs-7850-find-a-way-to-stream-incoming-tool-c…
Browse files Browse the repository at this point in the history
…all-code-and-thinking-ii
  • Loading branch information
lukemelia committed Mar 10, 2025
2 parents 621f598 + 160dab0 commit 753b50d
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 44 deletions.
2 changes: 1 addition & 1 deletion packages/boxel-ui/addon/src/components/button/index.gts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export default class ButtonComponent extends Component<Signature> {
height: min-content;
align-items: center;
border-radius: 100px;
white-space: nowrap;
word-break: var(--boxel-button-word-break, break-word);
transition:
background-color var(--boxel-transition),
border var(--boxel-transition);
Expand Down
24 changes: 16 additions & 8 deletions packages/host/app/components/ai-assistant/chat-input/index.gts
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,14 @@ export default class AiAssistantChatInput extends Component<Signature> {
.chat-input {
height: var(--chat-input-height);
min-height: var(--chat-input-height);
max-height: 300px;
border-color: transparent;
font-weight: 500;
padding: var(--boxel-sp-4xs);
resize: none;
outline: 0;
transition: height 0.2s ease-in-out;
overflow-y: auto;
}
.chat-input::placeholder {
color: var(--boxel-400);
Expand Down Expand Up @@ -134,17 +137,22 @@ export default class AiAssistantChatInput extends Component<Signature> {
get height() {
const lineHeight = 20;
const padding = 8;
const minLines = 1;
const maxLines = 15;

let lineCount = (this.args.value.match(/\n/g) ?? []).length + 1;
let count = 1;
// Calculate actual line count from newlines in the content
let newlineCount = (this.args.value.match(/\n/g) ?? []).length;

if (lineCount > 5) {
count = 5;
} else if (lineCount > 1) {
count = lineCount;
}
// Also consider content length for lines that might wrap
// This is a rough estimate that can be adjusted
const charsPerLine = 60;
let charLineCount = Math.ceil(this.args.value.length / charsPerLine);

// Use whichever count is higher (newlines or character-based estimate)
let estimatedLineCount = Math.max(newlineCount + 1, charLineCount);
let lineCount = Math.min(Math.max(estimatedLineCount, minLines), maxLines);

let height = count * lineHeight + 2 * padding;
let height = lineCount * lineHeight + 2 * padding;
return `${height}px`;
}
}
6 changes: 5 additions & 1 deletion packages/host/app/components/matrix/room.gts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import { AiAssistantConversation } from '../ai-assistant/message';
import NewSession from '../ai-assistant/new-session';
import AiAssistantSkillMenu from '../ai-assistant/skill-menu';

import { Submodes } from '../submode-switcher';

import RoomMessage from './room-message';

import type RoomData from '../../lib/matrix-classes/room';
Expand Down Expand Up @@ -300,7 +302,9 @@ export default class Room extends Component<Signature> {
}

private get autoAttachedFile() {
return this.autoAttachedFileResource.value;
return this.operatorModeStateService.state.submode === Submodes.Code
? this.autoAttachedFileResource.value
: undefined;
}

private get removeAutoAttachedFile() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Component from '@glimmer/component';

import { LoadingIndicator } from '@cardstack/boxel-ui/components';

import { type ResolvedCodeRef } from '@cardstack/runtime-common/code-ref';
import { type CodeRef } from '@cardstack/runtime-common/code-ref';
import { ModuleSyntax } from '@cardstack/runtime-common/module-syntax';

import CardSchemaEditor from '@cardstack/host/components/operator-mode/card-schema-editor';
Expand All @@ -24,8 +24,9 @@ interface Signature {
moduleSyntax: ModuleSyntax;
isReadOnly: boolean;
goToDefinition: (
codeRef: ResolvedCodeRef | undefined,
codeRef: CodeRef | undefined,
localName: string | undefined,
fieldName?: string,
) => void;
isLoading: boolean;
};
Expand Down
61 changes: 55 additions & 6 deletions packages/host/app/components/operator-mode/card-schema-editor.gts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { ArrowTopLeft, IconLink, IconPlus } from '@cardstack/boxel-ui/icons';

import { getPlural } from '@cardstack/runtime-common';

import { type ResolvedCodeRef } from '@cardstack/runtime-common/code-ref';
import { type CodeRef } from '@cardstack/runtime-common/code-ref';
import type { ModuleSyntax } from '@cardstack/runtime-common/module-syntax';

import EditFieldModal from '@cardstack/host/components/operator-mode/edit-field-modal';
Expand Down Expand Up @@ -57,8 +57,9 @@ interface Signature {
childFields: string[];
parentFields: string[];
goToDefinition: (
codeRef: ResolvedCodeRef | undefined,
codeRef: CodeRef | undefined,
localName: string | undefined,
fieldName?: string,
) => void;
};
}
Expand Down Expand Up @@ -91,6 +92,8 @@ export default class CardSchemaEditor extends Component<Signature> {
border-radius: var(--code-mode-container-border-radius);
background-color: var(--boxel-light);
overflow: hidden;
cursor: pointer;
width: 100%;
}
.card-field + .card-field {
margin-top: var(--boxel-sp-xxs);
Expand Down Expand Up @@ -163,6 +166,13 @@ export default class CardSchemaEditor extends Component<Signature> {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
border: none;
background-color: transparent;
padding: 0;
text-align: left;
}
.field-name:hover {
color: var(--boxel-highlight);
}
.overridden-field {
Expand Down Expand Up @@ -244,7 +254,10 @@ export default class CardSchemaEditor extends Component<Signature> {
<Pill
class='field-pill'
@kind='button'
{{on 'click' (fn @goToDefinition codeRef @cardType.localName)}}
{{on
'click'
(fn @goToDefinition codeRef @cardType.localName undefined)
}}
data-test-card-schema-navigational-button
>
<:iconLeft>
Expand Down Expand Up @@ -293,15 +306,17 @@ export default class CardSchemaEditor extends Component<Signature> {
data-test-field-name={{field.name}}
>
<div class='left'>
<div
<button
class={{if
(this.isOverridden field)
'field-name overridden-field'
'field-name'
}}
data-test-field-name-button={{field.name}}
{{on 'click' (fn this.goToField field)}}
>
{{field.name}}
</div>
</button>
<div class='field-types' data-test-field-types>
{{this.fieldTypes field}}
</div>
Expand Down Expand Up @@ -333,7 +348,12 @@ export default class CardSchemaEditor extends Component<Signature> {
@kind='button'
{{on
'click'
(fn @goToDefinition codeRef field.card.localName)
(fn
@goToDefinition
codeRef
field.card.localName
undefined
)
}}
data-test-card-schema-field-navigational-button
>
Expand Down Expand Up @@ -544,4 +564,33 @@ export default class CardSchemaEditor extends Component<Signature> {
inline: 'nearest',
});
}

@action
private goToField(field: FieldOfType) {
if (
`${this.args.cardType.module}.gts` ===
this.operatorModeStateService.codePathString
) {
// In the same file
this.args.goToDefinition(
undefined,
this.args.cardType.localName,
field.name,
);
return;
}

let codeRef = getCodeRef(this.args.cardType);
if (!codeRef) {
return undefined;
}
this.args.goToDefinition(
{
type: 'fieldOf',
card: codeRef,
field: field.name,
},
this.args.cardType.localName,
);
}
}
62 changes: 54 additions & 8 deletions packages/host/app/components/operator-mode/code-editor.gts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ interface Signature {
saveSourceOnClose: (url: URL, content: string) => void;
selectDeclaration: (declaration: ModuleDeclaration) => void;
onFileSave: (status: 'started' | 'finished') => void;
onSetup: (updateCursorByName: (name: string) => void) => void;
onSetup: (
updateCursorByName: (name: string, fieldName?: string) => void,
) => void;
};
}

Expand Down Expand Up @@ -137,12 +139,36 @@ export default class CodeEditor extends Component<Signature> {
}
}

let selectedFieldName = this.operatorModeStateService.state.fieldSelection;
let { selectedDeclaration } = this.args;
if (
selectedFieldName &&
selectedDeclaration &&
'possibleFields' in selectedDeclaration &&
selectedDeclaration.possibleFields
) {
let possibleFields = selectedDeclaration.possibleFields;
let field = possibleFields.get(selectedFieldName);
let loc =
field?.path?.node && 'loc' in field.path.node && field.path.node.loc
? field.path.node.loc
: undefined;
if (loc) {
let { start } = loc;
let { line, column } = start;
// Adjusts column to make cursor position right after the field name
let fieldDecoratorTextLength = 8;
column = column + fieldDecoratorTextLength + selectedFieldName.length;
return new Position(line, column);
}
}

let loc =
this.args.selectedDeclaration?.path?.node &&
'body' in this.args.selectedDeclaration.path.node &&
'loc' in this.args.selectedDeclaration.path.node.body &&
this.args.selectedDeclaration.path.node.body.loc
? this.args.selectedDeclaration?.path?.node.body.loc
selectedDeclaration?.path?.node &&
'body' in selectedDeclaration.path.node &&
'loc' in selectedDeclaration.path.node.body &&
selectedDeclaration.path.node.body.loc
? selectedDeclaration?.path?.node.body.loc
: undefined;
if (loc) {
let { start } = loc;
Expand All @@ -152,17 +178,37 @@ export default class CodeEditor extends Component<Signature> {
}

@action
private updateMonacoCursorPositionByName(name: string) {
private updateMonacoCursorPositionByName(name: string, fieldName?: string) {
let declaration = findDeclarationByName(name, this.declarations);
if (declaration === undefined) return;
return this.updateMonacoCursorPositionByDeclaration(declaration);
return this.updateMonacoCursorPositionByDeclaration(declaration, fieldName);
}

@action
private updateMonacoCursorPositionByDeclaration(
declaration: ModuleDeclaration,
fieldName?: string,
) {
if (
fieldName &&
'possibleFields' in declaration &&
declaration.possibleFields
) {
let possibleFields = declaration.possibleFields;
let field = possibleFields.get(fieldName);
let loc =
field?.path?.node && 'loc' in field.path.node && field.path.node.loc
? field.path.node.loc
: undefined;
if (loc) {
// Adjusts column to make cursor position right after the field name
let fieldDecoratorTextLength = 8;
let columnAdjustment = fieldDecoratorTextLength + fieldName.length;
this.monacoService.updateCursorPosition(
new Position(loc.start.line, loc.start.column + columnAdjustment),
);
}
} else if (
declaration.path?.node &&
'body' in declaration.path.node &&
'loc' in declaration.path.node.body &&
Expand Down
24 changes: 16 additions & 8 deletions packages/host/app/components/operator-mode/code-submode.gts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
isResolvedCodeRef,
type ResolvedCodeRef,
PermissionsContextName,
CodeRef,
} from '@cardstack/runtime-common';
import { isEquivalentBodyPosition } from '@cardstack/runtime-common/schema-analysis-plugin';

Expand Down Expand Up @@ -158,7 +159,9 @@ export default class CodeSubmode extends Component<Signature> {

private defaultPanelWidths: PanelWidths;
private defaultPanelHeights: PanelHeights;
private updateCursorByName: ((name: string) => void) | undefined;
private updateCursorByName:
| ((name: string, fieldName?: string) => void)
| undefined;
private panelSelections: Record<string, SelectedAccordionItem>;

private createFileModal: CreateFileModal | undefined;
Expand Down Expand Up @@ -497,10 +500,11 @@ export default class CodeSubmode extends Component<Signature> {

@action
private goToDefinitionAndResetCursorPosition(
codeRef: ResolvedCodeRef | undefined,
codeRef: CodeRef | undefined,
localName: string | undefined,
fieldName?: string,
) {
this.goToDefinition(codeRef, localName);
this.goToDefinition(codeRef, localName, fieldName);
if (this.codePath) {
let urlString = this.codePath.toString();
this.recentFilesService.updateCursorPositionByURL(
Expand All @@ -512,14 +516,16 @@ export default class CodeSubmode extends Component<Signature> {

@action
private goToDefinition(
codeRef: ResolvedCodeRef | undefined,
codeRef: CodeRef | undefined,
localName: string | undefined,
fieldName?: string,
) {
this.operatorModeStateService.updateCodePathWithCodeSelection(
this.operatorModeStateService.updateCodePathWithSelection({
codeRef,
localName,
this.updateCursorByName,
);
fieldName,
onLocalSelection: this.updateCursorByName,
});
}

private loadScopedCSS = restartableTask(async () => {
Expand Down Expand Up @@ -713,7 +719,9 @@ export default class CodeSubmode extends Component<Signature> {
this.createFileModal = createFileModal;
};

private setupCodeEditor = (updateCursorByName: (name: string) => void) => {
private setupCodeEditor = (
updateCursorByName: (name: string, fieldName?: string) => void,
) => {
this.updateCursorByName = updateCursorByName;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Component from '@glimmer/component';
import { cached } from '@glimmer/tracking';

import { getPlural } from '@cardstack/runtime-common';
import { type ResolvedCodeRef } from '@cardstack/runtime-common/code-ref';
import { type CodeRef } from '@cardstack/runtime-common/code-ref';

import { ModuleSyntax } from '@cardstack/runtime-common/module-syntax';

Expand All @@ -30,8 +30,9 @@ interface Signature {
card: typeof BaseDef;
isReadOnly: boolean;
goToDefinition: (
codeRef: ResolvedCodeRef | undefined,
codeRef: CodeRef | undefined,
localName: string | undefined,
fieldName?: string,
) => void;
};
Blocks: {
Expand Down
Loading

0 comments on commit 753b50d

Please sign in to comment.