Skip to content

Commit 8e34c2e

Browse files
authored
feat: revamp infoview options and actions (#606)
This PR revamps the option and action UX of the InfoView. This work is motivated by several reports from users that they never knew that certain InfoView functionality existed, and intends to make these features more discoverable. Closes #592. Specifically, the following adjustments are made: - The filter menu was difficult to discover and users had trouble finding the 'reverse tactic state' functionality. To improve this, all goal state settings have been moved into a single 'Settings' menu that uses a standard cog icon, which should hopefully be much more recognizable. - All goal state settings are now also available in the 'Settings' submenu of the InfoView context menu. - The 'Unselect All' context menu entry is now only visible when there is something to be unselected, as is the case for other context menu entries. - All goal state settings can be persisted to the VS Code user settings with a context menu action or a button in the settings menu. Clients that do not support this functionality can hide the button in the settings menu by hiding the elements with `saveConfigButton` and `saveConfigLineBreak` classes. - The `reverseTacticState`, `showGoalNames` and `emphasizeFirstGoal` settings have been made available in the InfoView goal state settings menu. - All InfoView actions have been made available in the context menu. - The 'Copy to comment' and 'Copy to clipboard' actions have been removed. As of [vscode#206529](microsoft/vscode#206529), copying from VS Code webviews should work correctly out-of-the-box, so there is no need for these additional buttons that may unnecessarily complicate the UI anymore. - The 'Refresh' action has been adjusted so that it is only displayed when the InfoView is paused to explicitly hint at the fact that it can be used to refresh the goal state while the InfoView is paused. Many users used to think that this was just the "Retry if InfoView is broken" button, which is practically never necessary. - The tooltips of all InfoView icons have been adjusted to be a bit more descriptive. - The `lean4.infoview.showExpectedType` setting has been deprecated in favor of the new `lean4.infoview.expectedTypeVisibility` setting, which allows hiding the expected type section entirely, as this section was reported to be confusing for students in a teaching environment. <details> <summary>Adjusted InfoView UI (Click to open)</summary> ![Adjusted InfoView UI](https://github.com/user-attachments/assets/3988695f-ff5b-4355-92fa-fdd62aae6cae) </details> <details> <summary>New settings menu (Click to open)</summary> ![New settings menu](https://github.com/user-attachments/assets/14721d72-f9c3-423e-a642-40a1e12348a6) </details> <details> <summary>New InfoView context menu (Click to open)</summary> ![New InfoView context menu](https://github.com/user-attachments/assets/e7b7b129-b74a-40f9-9fd6-63db2d4bba5e) </details>
1 parent d310b9c commit 8e34c2e

File tree

14 files changed

+950
-185
lines changed

14 files changed

+950
-185
lines changed

lean4-infoview-api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@leanprover/infoview-api",
3-
"version": "0.6.0",
3+
"version": "0.7.0",
44
"description": "Types and API for @leanprover/infoview.",
55
"scripts": {
66
"watch": "tsc --watch",

lean4-infoview-api/src/infoviewApi.ts

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@ import type {
77
WorkspaceEdit,
88
} from 'vscode-languageserver-protocol'
99

10+
export type ExpectedTypeVisibility = 'Expanded by default' | 'Collapsed by default' | 'Hidden'
11+
12+
export interface InfoviewConfig {
13+
allErrorsOnLine: boolean
14+
autoOpenShowsGoal: boolean
15+
debounceTime: number
16+
expectedTypeVisibility: ExpectedTypeVisibility
17+
showGoalNames: boolean
18+
emphasizeFirstGoal: boolean
19+
reverseTacticState: boolean
20+
hideTypeAssumptions: boolean
21+
hideInstanceAssumptions: boolean
22+
hideInaccessibleAssumptions: boolean
23+
hideLetValues: boolean
24+
showTooltipOnHover: boolean
25+
}
26+
1027
/**
1128
* An insert `here` should be written exactly at the specified position,
1229
* while one `above` should go on the preceding line.
@@ -15,6 +32,8 @@ export type TextInsertKind = 'here' | 'above'
1532

1633
/** Interface that the InfoView WebView uses to talk to the hosting editor. */
1734
export interface EditorApi {
35+
saveConfig(config: InfoviewConfig): Promise<any>
36+
1837
/** Make a request to the LSP server. */
1938
sendClientRequest(uri: string, method: string, params: any): Promise<any>
2039
/** Send a notification to the LSP server. */
@@ -77,25 +96,18 @@ export interface InfoviewTacticStateFilter {
7796
flags: string
7897
}
7998

80-
export interface InfoviewConfig {
81-
allErrorsOnLine: boolean
82-
autoOpenShowsGoal: boolean
83-
debounceTime: number
84-
showExpectedType: boolean
85-
showGoalNames: boolean
86-
emphasizeFirstGoal: boolean
87-
reverseTacticState: boolean
88-
showTooltipOnHover: boolean
89-
}
90-
9199
export const defaultInfoviewConfig: InfoviewConfig = {
92100
allErrorsOnLine: true,
93101
autoOpenShowsGoal: true,
94102
debounceTime: 50,
95-
showExpectedType: true,
103+
expectedTypeVisibility: 'Expanded by default',
96104
showGoalNames: true,
97105
emphasizeFirstGoal: false,
98106
reverseTacticState: false,
107+
hideTypeAssumptions: false,
108+
hideInstanceAssumptions: false,
109+
hideInaccessibleAssumptions: false,
110+
hideLetValues: false,
99111
showTooltipOnHover: true,
100112
}
101113

@@ -108,7 +120,35 @@ export type InfoviewActionKind =
108120

109121
export type InfoviewAction = { kind: InfoviewActionKind }
110122

111-
export type ContextMenuEntry = 'goToDefinition' | 'select' | 'unselect' | 'unselectAll'
123+
export type ContextMenuEntry =
124+
| 'goToDefinition'
125+
| 'select'
126+
| 'unselect'
127+
| 'unselectAll'
128+
| 'pause'
129+
| 'unpause'
130+
| 'pin'
131+
| 'unpin'
132+
| 'refresh'
133+
| 'pauseAllMessages'
134+
| 'unpauseAllMessages'
135+
| 'goToPinnedLocation'
136+
| 'goToMessageLocation'
137+
| 'displayTargetBeforeAssumptions'
138+
| 'displayAssumptionsBeforeTarget'
139+
| 'hideTypeAssumptions'
140+
| 'showTypeAssumptions'
141+
| 'hideInstanceAssumptions'
142+
| 'showInstanceAssumptions'
143+
| 'hideInaccessibleAssumptions'
144+
| 'showInaccessibleAssumptions'
145+
| 'hideLetValues'
146+
| 'showLetValues'
147+
| 'hideGoalNames'
148+
| 'showGoalNames'
149+
| 'emphasizeFirstGoal'
150+
| 'deemphasizeFirstGoal'
151+
| 'saveSettings'
112152

113153
export interface ContextMenuAction {
114154
entry: ContextMenuEntry

lean4-infoview/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@leanprover/infoview",
3-
"version": "0.8.3",
3+
"version": "0.8.4",
44
"description": "An interactive display for the Lean 4 theorem prover.",
55
"scripts": {
66
"watch": "rollup --config --environment NODE_ENV:development --watch",
@@ -49,7 +49,7 @@
4949
"typescript": "^5.4.5"
5050
},
5151
"dependencies": {
52-
"@leanprover/infoview-api": "~0.6.0",
52+
"@leanprover/infoview-api": "~0.7.0",
5353
"@vscode/codicons": "^0.0.32",
5454
"@vscode-elements/react-elements": "^0.5.0",
5555
"es-module-lexer": "^1.5.4",

lean4-infoview/src/infoview/collapsing.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,24 @@ export function useIsVisible(): [(element: HTMLElement) => void, boolean] {
2626
return [node, isVisible]
2727
}
2828

29-
interface DetailsProps {
29+
interface DetailsProps extends React.PropsWithoutRef<React.HTMLProps<HTMLDetailsElement>> {
3030
initiallyOpen?: boolean
3131
children: [React.ReactNode, ...React.ReactNode[]]
3232
setOpenRef?: (_: React.Dispatch<React.SetStateAction<boolean>>) => void
3333
}
3434

3535
/** Like `<details>` but can be programatically revealed using `setOpenRef`.
3636
* The first child is placed inside the `<summary>` node. */
37-
export function Details({ initiallyOpen, children: [summary, ...children], setOpenRef }: DetailsProps): JSX.Element {
37+
export function Details({
38+
initiallyOpen,
39+
children: [summary, ...children],
40+
setOpenRef,
41+
...props
42+
}: DetailsProps): JSX.Element {
3843
const [isOpen, setOpen] = React.useState<boolean>(initiallyOpen === undefined ? false : initiallyOpen)
3944
if (setOpenRef) setOpenRef(setOpen)
4045
return (
41-
<details open={isOpen}>
46+
<details open={isOpen} {...props}>
4247
<summary
4348
className="mv2 pointer "
4449
onClick={e => {

0 commit comments

Comments
 (0)