Skip to content

Commit

Permalink
fix: handle no raw mode
Browse files Browse the repository at this point in the history
  • Loading branch information
julien-capellari committed Nov 24, 2023
1 parent 0fb61c1 commit 1aa2c5e
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 46 deletions.
32 changes: 32 additions & 0 deletions src/ui/task-tree-full-spinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { TaskManager } from '@jujulego/tasks';
import { Box, Text } from 'ink';

import { useFlatTaskTree } from '@/src/ui/hooks/useFlatTaskTree.ts';
import TaskSpinner from '@/src/ui/task-spinner.tsx';
import TaskTreeStats from '@/src/ui/task-tree-stats.tsx';

// Types
export interface TaskTreeFullSpinnerProps {
readonly manager: TaskManager;
}

// Component
export default function TaskTreeFullSpinner({ manager }: TaskTreeFullSpinnerProps) {
const flat = useFlatTaskTree(manager);

// Render
return (
<>
<Box flexDirection="column">
{ flat.map(({ task, level }) => (
<Box key={task.id} marginLeft={level * 2} flexShrink={0}>
<TaskSpinner task={task} />
</Box>
)) }
</Box>
<Text>
<TaskTreeStats manager={manager} />
</Text>
</>
);
}
65 changes: 65 additions & 0 deletions src/ui/task-tree-scrollable-spinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { TaskManager } from '@jujulego/tasks';
import { Box, Text, useInput } from 'ink';
import { useEffect, useMemo, useState } from 'react';

import { useStdoutDimensions } from '@/src/ui/hooks/useStdoutDimensions.ts';
import { useFlatTaskTree } from '@/src/ui/hooks/useFlatTaskTree.ts';
import TaskSpinner from '@/src/ui/task-spinner.tsx';
import TaskTreeStats from '@/src/ui/task-tree-stats.tsx';

// Types
export interface TaskTreeScrollableSpinnerProps {
readonly manager: TaskManager;
}

// Component
export default function TaskTreeScrollableSpinner({ manager }: TaskTreeScrollableSpinnerProps) {
const { rows: termHeight } = useStdoutDimensions();

// Extract all tasks
const flat = useFlatTaskTree(manager);

const maxHeight = useMemo(
() => Math.min(termHeight - 4, flat.length),
[termHeight, flat]
);

// Manage scroll
const [start, setStart] = useState(0);

const slice = useMemo(
() => flat.slice(start, start + maxHeight),
[flat, start, maxHeight]
);

useEffect(() => {
if (start + maxHeight > flat.length) {
setStart(Math.max(flat.length - maxHeight, 0));
}
}, [start, flat, maxHeight]);

useInput((_, key) => {
if (key.upArrow) {
setStart((old) => Math.max(0, old - 1));
} else if (key.downArrow) {
setStart((old) => Math.min(flat.length - maxHeight, old + 1));
}
});

// Render
return (
<>
<Box flexDirection="column">
{ slice.map(({ task, level }) => (
<Box key={task.id} marginLeft={level * 2} flexShrink={0}>
<TaskSpinner task={task} />
</Box>
)) }
</Box>
<Text>
<TaskTreeStats manager={manager} />
{ (maxHeight < flat.length) && (<Text color="grey"> - use keyboard arrows to scroll</Text>) }
</Text>
</>
);
}
54 changes: 9 additions & 45 deletions src/ui/task-tree-spinner.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { TaskManager } from '@jujulego/tasks';
import { Box, Text, useInput } from 'ink';
import { useEffect, useMemo, useState } from 'react';
import { useStdin } from 'ink';

import { useStdoutDimensions } from '@/src/ui/hooks/useStdoutDimensions.ts';
import { useFlatTaskTree } from '@/src/ui/hooks/useFlatTaskTree.ts';
import TaskSpinner from '@/src/ui/task-spinner.tsx';
import TaskTreeStats from '@/src/ui/task-tree-stats.tsx';
import TaskTreeScrollableSpinner from '@/src/ui/task-tree-scrollable-spinner.tsx';
import TaskTreeFullSpinner from '@/src/ui/task-tree-full-spinner.tsx';

// Types
export interface TaskTreeSpinnerProps {
Expand All @@ -14,44 +11,11 @@ export interface TaskTreeSpinnerProps {

// Component
export default function TaskTreeSpinner({ manager }: TaskTreeSpinnerProps) {
// Extract all tasks
const flat = useFlatTaskTree(manager);
const stdin = useStdin();

// Manage scroll
const [start, setStart] = useState(0);

const { rows: termHeight } = useStdoutDimensions();
const maxHeight = useMemo(() => Math.min(termHeight - 4, flat.length), [termHeight, flat]);
const slice = useMemo(() => flat.slice(start, start + maxHeight), [flat, start, maxHeight]);

useEffect(() => {
if (start + maxHeight > flat.length) {
setStart(Math.max(flat.length - maxHeight, 0));
}
}, [start, flat, maxHeight]);

useInput((_, key) => {
if (key.upArrow) {
setStart((old) => Math.max(0, old - 1));
} else if (key.downArrow) {
setStart((old) => Math.min(flat.length - maxHeight, old + 1));
}
});

// Render
return (
<>
<Box flexDirection="column">
{ slice.map(({ task, level }) => (
<Box key={task.id} marginLeft={level * 2} flexShrink={0}>
<TaskSpinner task={task} />
</Box>
)) }
</Box>
<Text>
<TaskTreeStats manager={manager} />
{ (maxHeight < flat.length) && (<Text color="grey"> - use keyboard arrows to scroll</Text>) }
</Text>
</>
);
if (stdin.isRawModeSupported) {
return <TaskTreeScrollableSpinner manager={manager} />;
} else {
return <TaskTreeFullSpinner manager={manager} />;
}
}
4 changes: 3 additions & 1 deletion tests/commands/each.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ afterEach(() => {

// Tests
describe('jill each', () => {
it('should run script in all workspaces having that script', async () => {
it.only('should run script in all workspaces having that script', async () => {
context.reset({});

// Setup workspaces
Expand Down Expand Up @@ -94,6 +94,8 @@ describe('jill each', () => {
expect(manager.add).toHaveBeenCalledWith(tasks[0]);
expect(manager.add).toHaveBeenCalledWith(tasks[1]);

await flushPromises();

// should print task spinners
expect(app.lastFrame()).toMatchLines([
expect.ignoreColor(/^. Run cmd in wks-1$/),
Expand Down

0 comments on commit 1aa2c5e

Please sign in to comment.