Compare commits

...

5 Commits

Author SHA1 Message Date
Mathew Pareles baa89cc17d dummy marker service 2025-02-18 14:14:38 -08:00
Mathew Pareles d3aa0bc3cc fix readfile 2025-02-17 17:56:20 -08:00
Mathew Pareles b92420012c minor 2025-02-17 15:18:11 -08:00
Mathew Pareles 89d08071fc scrollbar fix 2025-02-17 00:23:48 -08:00
Mathew Pareles 74f8303803 discard star changes 2025-02-16 20:11:13 -08:00
7 changed files with 220 additions and 109 deletions
@@ -432,7 +432,7 @@ export class UnpinEditorAction extends Action {
label: string,
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, ThemeIcon.asClassName(Codicon.starFull));
super(id, label, ThemeIcon.asClassName(Codicon.pinned));
}
override run(context?: IEditorCommandsContext): Promise<void> {
@@ -440,24 +440,6 @@ export class UnpinEditorAction extends Action {
}
}
export class PinEditorAction extends Action {
static readonly ID = 'workbench.action.pinEditor';
static readonly LABEL = localize('pinEditor', "Pin Editor");
constructor(
id: string,
label: string,
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, ThemeIcon.asClassName(Codicon.star));
}
override async run(context?: IEditorCommandsContext): Promise<void> {
return this.commandService.executeCommand('workbench.action.pinEditor', undefined, context);
}
}
export class CloseEditorTabAction extends Action {
static readonly ID = 'workbench.action.closeActiveEditor';
@@ -385,7 +385,7 @@
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-shrink > .tab-actions,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.tab-actions-right.sizing-fixed > .tab-actions {
flex: 0;
overflow: visible; /* ensure tab actions are always visible */
overflow: hidden; /* let the tab actions be pushed out of view when sizing is set to shrink/fixed to make more room */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty.tab-actions-right.sizing-shrink > .tab-actions,
@@ -399,8 +399,18 @@
overflow: visible; /* ...but still show the tab actions on hover, focus and when dirty or sticky */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-action-off:not(.dirty) > .tab-actions,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sticky-compact > .tab-actions {
display: none; /* only hide tab actions when sticky-compact */
display: none; /* hide the tab actions when we are configured to hide it (unless dirty, but always when sticky-compact) */
}
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.active > .tab-actions .action-label, /* always show tab actions for active tab */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab > .tab-actions .action-label:focus, /* always show tab actions on focus */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab:hover > .tab-actions .action-label, /* always show tab actions on hover */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.active:hover > .tab-actions .action-label, /* always show tab actions on hover */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.sticky:not(.pinned-action-off) > .tab-actions .action-label, /* always show tab actions for sticky tabs */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-actions .action-label { /* always show tab actions for dirty tabs */
opacity: 1;
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-actions .actions-container {
@@ -434,11 +444,11 @@
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-actions .action-label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sticky:not(.pinned-action-off) > .tab-actions .action-label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover > .tab-actions .action-label {
opacity: 1;
opacity: 0.5; /* show tab actions dimmed for inactive group */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-actions .action-label {
opacity: 1;
opacity: 0;
}
/* Tab Actions: Off */
@@ -35,7 +35,7 @@ import { MergeGroupMode, IMergeGroupOptions } from '../../../services/editor/com
import { addDisposableListener, EventType, EventHelper, Dimension, scheduleAtNextAnimationFrame, findParentWithClass, clearNode, DragAndDropObserver, isMouseEvent, getWindow } from '../../../../base/browser/dom.js';
import { localize } from '../../../../nls.js';
import { IEditorGroupsView, EditorServiceImpl, IEditorGroupView, IInternalEditorOpenOptions, IEditorPartsView } from './editor.js';
import { CloseEditorTabAction, PinEditorAction, UnpinEditorAction } from './editorActions.js';
import { CloseEditorTabAction, UnpinEditorAction } from './editorActions.js';
import { assertAllDefined, assertIsDefined } from '../../../../base/common/types.js';
import { IEditorService } from '../../../services/editor/common/editorService.js';
import { basenameOrAuthority } from '../../../../base/common/resources.js';
@@ -113,7 +113,6 @@ export class MultiEditorTabsControl extends EditorTabsControl {
private readonly closeEditorAction = this._register(this.instantiationService.createInstance(CloseEditorTabAction, CloseEditorTabAction.ID, CloseEditorTabAction.LABEL));
private readonly unpinEditorAction = this._register(this.instantiationService.createInstance(UnpinEditorAction, UnpinEditorAction.ID, UnpinEditorAction.LABEL));
private readonly pinEditorAction = this._register(this.instantiationService.createInstance(PinEditorAction, PinEditorAction.ID, PinEditorAction.LABEL)); // Add this line
private readonly tabResourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER));
private tabLabels: IEditorInputLabel[] = [];
@@ -1519,28 +1518,28 @@ export class MultiEditorTabsControl extends EditorTabsControl {
this.redrawTabLabel(editor, tabIndex, tabContainer, tabLabelWidget, tabLabel);
// Action
const hasCloseAction = options.tabActionCloseVisibility;
const hasAction = true; // Always show actions
const hasUnpinAction = isTabSticky && options.tabActionUnpinVisibility;
const hasCloseAction = !hasUnpinAction && options.tabActionCloseVisibility;
const hasAction = hasUnpinAction || hasCloseAction;
// Determine which action to show
let tabAction;
if (isTabSticky) {
tabAction = this.unpinEditorAction;
if (hasAction) {
tabAction = hasUnpinAction ? this.unpinEditorAction : this.closeEditorAction;
} else {
tabAction = this.pinEditorAction; // Use pin action instead of close action
// Even if the action is not visible, add it as it contains the dirty indicator
tabAction = isTabSticky ? this.unpinEditorAction : this.closeEditorAction;
}
// Update action bar
if (!tabActionBar.hasAction(tabAction)) {
if (!tabActionBar.isEmpty()) {
tabActionBar.clear();
}
tabActionBar.push(tabAction, { icon: true, label: false, keybinding: this.getKeybindingLabel(tabAction) });
}
tabContainer.classList.toggle('sticky', isTabSticky);
tabContainer.classList.toggle(`pinned-action-off`, false);
tabContainer.classList.toggle(`close-action-off`, !hasCloseAction);
tabContainer.classList.toggle(`pinned-action-off`, isTabSticky && !hasUnpinAction);
tabContainer.classList.toggle(`close-action-off`, !hasUnpinAction && !hasCloseAction);
for (const option of ['left', 'right']) {
tabContainer.classList.toggle(`tab-actions-${option}`, hasAction && options.tabActionLocation === option);
@@ -0,0 +1,119 @@
/*--------------------------------------------------------------------------------------
* Copyright 2025 Glass Devtools, Inc. All rights reserved.
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
*--------------------------------------------------------------------------------------*/
import { Disposable } from '../../../../base/common/lifecycle.js';
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { IMarkerService, MarkerSeverity } from '../../../../platform/markers/common/markers.js';
import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';
import { ITextModelService } from '../../../../editor/common/services/resolverService.js';
import { Range } from '../../../../editor/common/core/range.js';
import { CancellationToken } from '../../../../base/common/cancellation.js';
import { CodeActionContext, CodeActionTriggerType } from '../../../../editor/common/languages.js';
export interface IMarkerCheckService {
readonly _serviceBrand: undefined;
}
export const IMarkerCheckService = createDecorator<IMarkerCheckService>('markerCheckService');
class MarkerCheckService extends Disposable implements IMarkerCheckService {
_serviceBrand: undefined;
constructor(
@IMarkerService private readonly _markerService: IMarkerService,
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
@ITextModelService private readonly _textModelService: ITextModelService,
) {
super();
setInterval(async () => {
const allMarkers = this._markerService.read();
const errors = allMarkers.filter(marker => marker.severity === MarkerSeverity.Error);
if (errors.length > 0) {
for (const error of errors) {
console.log(`----------------------------------------------`);
console.log(`${error.resource.toString()}: ${error.startLineNumber} ${error.message} ${error.severity}`); // ! all errors in the file
try {
// Get the text model for the file
const modelReference = await this._textModelService.createModelReference(error.resource);
const model = modelReference.object.textEditorModel;
// Create a range from the marker
const range = new Range(
error.startLineNumber,
error.startColumn,
error.endLineNumber,
error.endColumn
);
// Get code action providers for this model
const codeActionProvider = this._languageFeaturesService.codeActionProvider;
const providers = codeActionProvider.ordered(model);
if (providers.length > 0) {
// Request code actions from each provider
for (const provider of providers) {
const context: CodeActionContext = {
trigger: CodeActionTriggerType.Invoke, // keeping 'trigger' since it works
only: 'quickfix' // adding this to filter for quick fixes
};
const actions = await provider.provideCodeActions(
model,
range,
context,
CancellationToken.None
);
if (actions?.actions?.length) {
const quickFixes = actions.actions.filter(action => action.isPreferred); // ! all quickFixes for the error
const quickFixesForImports = actions.actions.filter(action => action.isPreferred && action.title.includes('import')); // ! all possible imports
quickFixesForImports
if (quickFixes.length > 0) {
console.log('Available Quick Fixes:');
quickFixes.forEach(action => {
console.log(`- ${action.title}`);
});
}
}
}
}
// Dispose the model reference
modelReference.dispose();
} catch (e) {
console.error('Error getting quick fixes:', e);
}
}
}
}, 5000);
}
// private _onMarkersChanged = (changedResources: readonly URI[]): void => {
// for (const resource of changedResources) {
// const markers = this._markerService.read({ resource });
// if (markers.length === 0) {
// console.log(`${resource.toString()}: No diagnostics`);
// continue;
// }
// console.log(`Diagnostics for ${resource.toString()}:`);
// markers.forEach(marker => this._logMarker(marker));
// }
// };
}
registerSingleton(IMarkerCheckService, MarkerCheckService, InstantiationType.Eager);
@@ -20,7 +20,7 @@ export const VSReadFile = async (modelService: IModelService, fileService: IFile
// read files from VSCode. preferred (but appears to only work if the model of this URI already exists. If it doesn't use the other function.)
export const _VSReadModel = async (modelService: IModelService, uri: URI): Promise<string | null> => {
// attempt to read saved model (sometimes doesn't work if page is reloaded)
// attempt to read saved model (doesn't work if application was reloaded...)
const model = modelService.getModel(uri)
if (model) {
return model.getValue(EndOfLinePreference.LF)
@@ -38,7 +38,12 @@ export const _VSReadModel = async (modelService: IModelService, uri: URI): Promi
}
export const _VSReadFileRaw = async (fileService: IFileService, uri: URI) => {
const res = await fileService.readFile(uri)
const str = res.value.toString()
return str
try {
const res = await fileService.readFile(uri)
const str = res.value.toString()
return str
} catch (e) {
return ''
}
}
@@ -703,7 +703,6 @@ const ChatBubble = ({ chatMessage, isLoading, messageIdx }: { chatMessage: ChatM
: role === 'user' ? `px-2 self-end w-fit max-w-full whitespace-pre-wrap` // user words should be pre
: role === 'assistant' ? `px-2 self-start w-full max-w-full` : ''
}
${role !== 'assistant' ? 'my-2' : ''}
`}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
@@ -19,90 +19,87 @@ export const useScrollbarStyles = (containerRef: React.MutableRefObject<HTMLDivE
...Array.from(containerRef.current?.querySelectorAll(overflowSelector) || [])
];
// Clean up existing elements first
// Apply basic styling to all elements
scrollElements.forEach(element => {
if ((element as any).__scrollbarCleanup) {
(element as any).__scrollbarCleanup();
}
element.classList.add('void-scrollable-element');
});
// Apply styles and listeners to each scroll element
// Only initialize fade effects for elements that haven't been initialized yet
scrollElements.forEach(element => {
// Add the scrollable class directly to the overflow element
element.classList.add('void-scrollable-element');
if (!(element as any).__scrollbarCleanup) {
let fadeTimeout: NodeJS.Timeout | null = null;
let fadeInterval: NodeJS.Timeout | null = null;
let fadeTimeout: NodeJS.Timeout | null = null;
let fadeInterval: NodeJS.Timeout | null = null;
const fadeIn = () => {
if (fadeInterval) clearInterval(fadeInterval);
const fadeIn = () => {
if (fadeInterval) clearInterval(fadeInterval);
let step = 0;
fadeInterval = setInterval(() => {
if (step <= 10) {
element.classList.remove(`show-scrollbar-${step - 1}`);
element.classList.add(`show-scrollbar-${step}`);
step++;
} else {
clearInterval(fadeInterval!);
}
}, 10);
};
let step = 0;
fadeInterval = setInterval(() => {
if (step <= 10) {
element.classList.remove(`show-scrollbar-${step - 1}`);
element.classList.add(`show-scrollbar-${step}`);
step++;
} else {
clearInterval(fadeInterval!);
const fadeOut = () => {
if (fadeInterval) clearInterval(fadeInterval);
let step = 10;
fadeInterval = setInterval(() => {
if (step >= 0) {
element.classList.remove(`show-scrollbar-${step + 1}`);
element.classList.add(`show-scrollbar-${step}`);
step--;
} else {
clearInterval(fadeInterval!);
}
}, 60);
};
const onMouseEnter = () => {
if (fadeTimeout) clearTimeout(fadeTimeout);
if (fadeInterval) clearInterval(fadeInterval);
fadeIn();
};
const onMouseLeave = () => {
if (fadeTimeout) clearTimeout(fadeTimeout);
fadeTimeout = setTimeout(() => {
fadeOut();
}, 10);
};
element.addEventListener('mouseenter', onMouseEnter);
element.addEventListener('mouseleave', onMouseLeave);
// Store cleanup function
const cleanup = () => {
element.removeEventListener('mouseenter', onMouseEnter);
element.removeEventListener('mouseleave', onMouseLeave);
if (fadeTimeout) clearTimeout(fadeTimeout);
if (fadeInterval) clearInterval(fadeInterval);
element.classList.remove('void-scrollable-element');
// Remove any remaining show-scrollbar classes
for (let i = 0; i <= 10; i++) {
element.classList.remove(`show-scrollbar-${i}`);
}
}, 10);
};
};
const fadeOut = () => {
if (fadeInterval) clearInterval(fadeInterval);
let step = 10;
fadeInterval = setInterval(() => {
if (step >= 0) {
element.classList.remove(`show-scrollbar-${step + 1}`);
element.classList.add(`show-scrollbar-${step}`);
step--;
} else {
clearInterval(fadeInterval!);
}
}, 60);
};
const onMouseEnter = () => {
if (fadeTimeout) clearTimeout(fadeTimeout);
if (fadeInterval) clearInterval(fadeInterval);
fadeIn();
};
const onMouseLeave = () => {
if (fadeTimeout) clearTimeout(fadeTimeout);
fadeTimeout = setTimeout(() => {
fadeOut();
}, 10);
};
element.addEventListener('mouseenter', onMouseEnter);
element.addEventListener('mouseleave', onMouseLeave);
// Store cleanup function
const cleanup = () => {
element.removeEventListener('mouseenter', onMouseEnter);
element.removeEventListener('mouseleave', onMouseLeave);
if (fadeTimeout) clearTimeout(fadeTimeout);
if (fadeInterval) clearInterval(fadeInterval);
element.classList.remove('void-scrollable-element');
// Remove any remaining show-scrollbar classes
for (let i = 0; i <= 10; i++) {
element.classList.remove(`show-scrollbar-${i}`);
}
};
// Store the cleanup function on the element for later use
(element as any).__scrollbarCleanup = cleanup;
// Store the cleanup function on the element for later use
(element as any).__scrollbarCleanup = cleanup;
}
});
};
// Initialize for the first time
initializeScrollbarStyles();
// Set up mutation observer
const observer = new MutationObserver((mutations) => {
// Set up mutation observer to do the same
const observer = new MutationObserver(() => {
initializeScrollbarStyles();
});