Skip to content

Commit

Permalink
feat: save cursor position with undo/redo (#455)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: David Kircos <davidkircos@gmail.com>
Co-authored-by: Jim Nielsen <jimniels@gmail.com>
  • Loading branch information
3 people committed May 10, 2023
1 parent 673c8ec commit 18815f3
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 9 deletions.
40 changes: 31 additions & 9 deletions src/grid/controller/sheetController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { StatementRunner } from './runners/runner';
import { PixiApp } from '../../gridGL/pixiApp/PixiApp';
import * as Sentry from '@sentry/browser';
import { debug } from '../../debugFlags';
import { GridInteractionState } from '../../atoms/gridInteractionStateAtom';

export class SheetController {
app?: PixiApp; // TODO: Untangle PixiApp from SheetController.
Expand Down Expand Up @@ -34,7 +35,7 @@ export class SheetController {
// execute_statement until end_transaction is called.
//

public start_transaction(): void {
public start_transaction(interactionState?: GridInteractionState): void {
if (this.transaction_in_progress) {
// during debug mode, throw an error
// otherwise, capture the error and continue
Expand All @@ -45,11 +46,20 @@ export class SheetController {
this.end_transaction();
}

// This is useful when the user clicks outside of the active cell to another
// cell, so the cursor moves to that new cell and the transaction finishes
let cursor = undefined;
if (interactionState) {
cursor = { ...interactionState, showInput: false };
} else if (this.app?.settings.interactionState) {
cursor = { ...this.app.settings.interactionState, showInput: false };
}

// set transaction in progress to a new Transaction
// transaction_in_progress represents the stack of commands needed
// to undo the transaction currently being executed.
this.transaction_in_progress = { statements: [] };
this.transaction_in_progress_reverse = { statements: [] };
this.transaction_in_progress = { statements: [], cursor };
this.transaction_in_progress_reverse = { statements: [], cursor };
}

public execute_statement(statement: Statement): void {
Expand Down Expand Up @@ -135,9 +145,15 @@ export class SheetController {
// add reverse transaction to redo stack
this.redo_stack.push(reverse_transaction);

// TODO: The transaction should keep track of everything that becomes dirty while executing and then just sets the correct flags on app.
// This will be very inefficient on large files.
if (this.app) this.app.rebuild();
if (this.app) {
if (transaction.cursor) {
this.app.settings.setInteractionState?.(transaction.cursor);
}

// TODO: The transaction should keep track of everything that becomes dirty while executing and then just sets the correct flags on app.
// This will be very inefficient on large files.
this.app.rebuild();
}
}

public redo(): void {
Expand Down Expand Up @@ -169,9 +185,15 @@ export class SheetController {
// add reverse transaction to undo stack
this.undo_stack.push(reverse_transaction);

// TODO: The transaction should keep track of everything that becomes dirty while executing and then just sets the correct flags on app.
// This will be very inefficient on large files.
if (this.app) this.app.rebuild();
if (this.app) {
if (transaction.cursor) {
this.app.settings.setInteractionState?.(transaction.cursor);
}

// TODO: The transaction should keep track of everything that becomes dirty while executing and then just sets the correct flags on app.
// This will be very inefficient on large files.
this.app.rebuild();
}
}

public clear(): void {
Expand Down
2 changes: 2 additions & 0 deletions src/grid/controller/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { GridInteractionState } from '../../atoms/gridInteractionStateAtom';
import { Statement } from './statement';

export type Transaction = {
statements: Statement[];
cursor?: GridInteractionState;
};
14 changes: 14 additions & 0 deletions src/gridGL/interaction/CellInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export const CellInput = (props: CellInputProps) => {

const [value, setValue] = useState<string | undefined>(undefined);

// used to save interaction state when input starts
const [saveInteractionState, setSaveInteractionState] = useState<GridInteractionState>();

const cellLocation = useRef(interactionState.cursorPosition);
const textInput = useRef<HTMLInputElement>(null);
// Effect for sizing the input width to the length of the value
Expand Down Expand Up @@ -82,6 +85,11 @@ export const CellInput = (props: CellInputProps) => {
return null;
}

// copy interaction state when input starts
if (!saveInteractionState) {
setSaveInteractionState(interactionState);
}

// need this variable to cancel second closeInput call from blur after pressing Escape (this happens before the state can update)
let closed = false;

Expand All @@ -91,6 +99,7 @@ export const CellInput = (props: CellInputProps) => {
closed = true;

if (!cancel) {
sheetController.start_transaction(saveInteractionState);
// Update Cell and dependent cells
if (value === '') {
// delete cell if input is empty, and wasn't empty before
Expand All @@ -102,6 +111,7 @@ export const CellInput = (props: CellInputProps) => {
y1: cellLocation.current.y,
sheetController,
app,
create_transaction: false,
});
} else {
// create cell with value at input location
Expand All @@ -116,8 +126,10 @@ export const CellInput = (props: CellInputProps) => {
],
sheetController,
app,
create_transaction: false,
});
}
sheetController.end_transaction();
app.quadrants.quadrantChanged({ cells: [cellLocation.current] });
}

Expand All @@ -137,6 +149,8 @@ export const CellInput = (props: CellInputProps) => {
});
setValue(undefined);

setSaveInteractionState(undefined);

// Set focus back to Grid
focusGrid();

Expand Down

1 comment on commit 18815f3

@vercel
Copy link

@vercel vercel bot commented on 18815f3 May 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

quadratic – ./

quadratic-git-main-quadratic.vercel.app
quadratic-quadratic.vercel.app
quadratic-nu.vercel.app

Please sign in to comment.