Skip to content
This repository has been archived by the owner on Jun 26, 2024. It is now read-only.

Infoview overhaul #159

Merged
merged 121 commits into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
653cca2
Readd translation `"X": "\u2A2F"`
EdAyers Mar 12, 2019
8e1dbec
New UI idea
EdAyers Apr 4, 2020
0354b72
Stash
EdAyers Apr 10, 2020
c55ff2b
Draft widget viewer.
EdAyers Apr 12, 2020
0c00b9e
Stash
EdAyers Apr 13, 2020
4cf365c
stuff
EdAyers Apr 14, 2020
2063efb
Add draft hover support.
EdAyers Apr 20, 2020
04c9f40
stash
EdAyers Apr 22, 2020
ef4ccfa
Fix issue with components being lists of htmls
EdAyers Apr 23, 2020
ae6b765
clean up
EdAyers Apr 23, 2020
d552ced
Merge branch 'widget' of bitbucket.org:ewa21/vscode-lean into widget
EdAyers Apr 23, 2020
b50a003
Tooltips
EdAyers Apr 26, 2020
7981694
Merge branch 'widget' of bitbucket.org:ewa21/vscode-lean into widget
EdAyers Apr 26, 2020
c72d8c4
Hovering works!
EdAyers Apr 26, 2020
ca35460
Tidy todos
EdAyers Apr 26, 2020
47b07e6
Add widget support
EdAyers Apr 4, 2020
e021fbc
Fix merge conflicts
EdAyers Apr 27, 2020
252ee4a
feat(widget): add textbox support
EdAyers Apr 29, 2020
844649f
Merge branch 'widget' of github.com:EdAyers/vscode-lean into widget
EdAyers Apr 29, 2020
1ae0d2b
Add tachyons CSS
EdAyers May 4, 2020
7bceb4e
Add ability for widget to insert text.
EdAyers May 6, 2020
4721406
Fix issue where invalid-handler causes app to 'freeze'.
EdAyers May 7, 2020
58d7150
Fix typescript not building
EdAyers May 7, 2020
d7da2de
Remove a widget-container style
EdAyers May 7, 2020
639283d
remove silly semicolon
EdAyers May 8, 2020
ef10b39
Add some docs
EdAyers May 8, 2020
4e23e2c
Use webpack to compile infoview
EdAyers May 8, 2020
2a3ce5d
Overhaul infoview look
EdAyers May 8, 2020
4ce69b1
Fix build warning
EdAyers May 8, 2020
4a9dbe6
Fix issue where not rerendering on handle error
EdAyers May 10, 2020
414577d
Merge branch 'master' of github.com:EdAyers/vscode-lean into widget
EdAyers May 10, 2020
2fb56d8
Merge branch 'master' of github.com:EdAyers/vscode-lean
EdAyers May 10, 2020
e3e7ce4
Merge branch 'widget' of github.com:EdAyers/vscode-lean into widget
EdAyers May 10, 2020
8f8e8a5
Merge branch 'master' into widget
EdAyers May 10, 2020
2c97241
Remove old readme for infoview
EdAyers May 10, 2020
b6dced9
Fix aesthetic issues
EdAyers May 10, 2020
7955b2d
Move compile to use webpack
EdAyers May 10, 2020
1d918ba
fix linting in infoview.ts
EdAyers May 10, 2020
ce4060b
Merge branch 'widget' of github.com:EdAyers/vscode-lean into widget
EdAyers May 10, 2020
7428c63
Update package-lock.json
EdAyers May 10, 2020
cb24104
Separate CSS in to different files to load by webpack
EdAyers May 11, 2020
2e2304c
Can view current tasks in infoview.I would like to add a feature to L…
EdAyers May 11, 2020
03e602f
Fix linter
EdAyers May 12, 2020
0b58e53
Style tweaks, remove the task view.
EdAyers May 12, 2020
145e155
Stash
EdAyers May 13, 2020
b5fddf6
Idea to use server.ts on the webview.
EdAyers May 13, 2020
09de11e
Fix warnings
EdAyers May 13, 2020
bb58302
Try to monkeypatch server to have a proxy connection.
EdAyers May 15, 2020
17717f8
Now uses server. Update widget renderer to use new API
EdAyers May 19, 2020
a50086d
Implement pinning
EdAyers May 19, 2020
d8222c9
Merge branch 'widget' into widget-dev
EdAyers May 19, 2020
d3a41bb
Merge branch 'master' of https://github.com/leanprover/vscode-lean
EdAyers May 19, 2020
510ab72
Merge branch 'master' into widget. Add pin tracking
EdAyers May 19, 2020
969e51f
Style details for hierarchy
EdAyers May 20, 2020
174ae85
Implement DisplayMode properly.It now works as follows: if the Displa…
EdAyers May 20, 2020
7e637cb
ConfigEvent accepts partial configs.
EdAyers May 20, 2020
cddb86d
Remove condition that goalview wouldn't render if displaymode was all…
EdAyers May 20, 2020
3a89a84
Fix copy to comment.
EdAyers May 20, 2020
5e1c9e7
Fix issue where goal state was not dissappearing.
EdAyers May 20, 2020
efedfc2
Add some minor style and aesthetic tweaks.
EdAyers May 27, 2020
8555ce9
Remove unused files from media.
EdAyers May 27, 2020
a3b2048
Reintroduce commented out commands.
EdAyers May 27, 2020
561228d
Fix goal not wrapping text.
EdAyers May 27, 2020
d621d60
Add error boundaries and some more error messages.
EdAyers May 28, 2020
5f6a4dd
Add icons to webview
EdAyers May 29, 2020
c61175d
Reduce margins
EdAyers May 29, 2020
f546b89
Change tactic state panel to be closed if there is a widget
EdAyers May 29, 2020
f35bee9
Add try again and multiple tries for invalidated error.
EdAyers May 29, 2020
6e17d9d
Merge branch 'master' into widget
EdAyers May 29, 2020
028dc29
Readd watch script
EdAyers May 29, 2020
387c776
Fix linting error
EdAyers May 29, 2020
286a17a
Add update status change state to info.
EdAyers May 31, 2020
a220f3f
Change default build task to compile
EdAyers May 31, 2020
2f61bce
Change the colour of the sidebar of infoview dependent on status.
EdAyers May 31, 2020
6ec58a4
Fix fill-rule -> fillRule
EdAyers May 31, 2020
588d959
Fix issue where multiple messages were assigned the same key.
EdAyers Jun 1, 2020
13f237e
Fix regression where info at position was not showing updates.
EdAyers Jun 1, 2020
7476556
Style: reduce margins.
EdAyers Jun 1, 2020
7c08375
style: change from pointer cursor on style
EdAyers Jun 8, 2020
52d1fd9
Changes for lean#301
gebner Jun 8, 2020
051490e
Remove now unnecessary retry loop.
gebner Jun 8, 2020
5cca0eb
Merge pull request #1 from leanprover/refactor_widget_event
EdAyers Jun 8, 2020
8c9a6ae
Merge branch 'widget' of github.com:EdAyers/vscode-lean into widget
EdAyers Jun 8, 2020
86180a6
Update to lean-client-js 1.3
EdAyers Jun 8, 2020
d3019e1
Fix linting error
EdAyers Jun 8, 2020
176ce75
Add a github action to build.
EdAyers Jun 8, 2020
50d59b3
Fix so action runs on push.
EdAyers Jun 8, 2020
0e1286e
Try adding ^1.3.0 for lean-client-js-core
EdAyers Jun 8, 2020
7695cc1
Increment lean-client-js
EdAyers Jun 8, 2020
cbeb381
Fix imports
EdAyers Jun 8, 2020
cdd26fd
Fix linting
EdAyers Jun 8, 2020
2853716
Merge branch 'master' into widget
EdAyers Jun 9, 2020
b232a9c
Remove `any`s from server calls.
EdAyers Jun 10, 2020
7598d13
Add copyToComment to messages
EdAyers Jun 10, 2020
4cebbfa
Remove toggleSticky and copytocomment from editor taskbar.
EdAyers Jun 10, 2020
bce4a76
Reduce spacing between infoview buttons
EdAyers Jun 10, 2020
42d1117
Fix clip-rule issue
EdAyers Jun 10, 2020
55be64a
Add restarter for infoview
EdAyers Jun 10, 2020
fc3b6f7
Bump lean-client-js version to 1.3.2
EdAyers Jun 10, 2020
7a0a5e6
Fix remaking a proxy connection when the server restarts.
EdAyers Jun 10, 2020
832fdae
Remove indentation from old-school tactic states.
gebner Jun 10, 2020
a920e75
Revert restarting webview server on extension server restart.
EdAyers Jun 10, 2020
e6a76d7
Merge remote-tracking branch 'origin/widget' into widget
EdAyers Jun 10, 2020
6e5b4f7
Support get_widget request.
gebner Jun 10, 2020
69c9c0d
Merge pull request #2 from leanprover/get_widget
EdAyers Jun 10, 2020
b50e302
Bump lean-client-js to 1.3.3
EdAyers Jun 10, 2020
9daaf57
Bump to lean-client-js 1.4.0
EdAyers Jun 10, 2020
c5723ee
Fix linting error.
gebner Jun 11, 2020
1a875b9
Also run actions on PRs.
gebner Jun 11, 2020
167b27d
Add better refresh logic to infoview
EdAyers Jun 13, 2020
641dec1
Merge remote-tracking branch 'origin/widget' into widget
EdAyers Jun 13, 2020
5ec739c
Fix linting
EdAyers Jun 13, 2020
8910717
Add a 'plaintext' clarification
EdAyers Jun 13, 2020
4b9e964
Add a 'throttle' to the location props.
EdAyers Jun 13, 2020
7fc1bb2
Remove red code marker when hovering over infoview
EdAyers Jun 13, 2020
6d7edd2
Also update info when all tasks are done.
EdAyers Jun 13, 2020
4ad5da8
Add a new event model for updating widgets.
EdAyers Jun 14, 2020
776bea2
Remove logging messages.
EdAyers Jun 14, 2020
da8944b
Add a more helpful message if there is no info but updating is paused.
EdAyers Jun 15, 2020
05fbaca
Add 'reveal file location' button.
EdAyers Jun 16, 2020
1308443
Fix issue where an empty error message would crash React.
EdAyers Jun 16, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module.exports = {
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"project": ["./tsconfig.json", "./infoview/tsconfig.json"],
"sourceType": "module"
},
"plugins": [
Expand Down Expand Up @@ -122,6 +122,7 @@ module.exports = {
"no-console": "off",
"no-debugger": "error",
"no-empty": "off",
"ban-ts-ignore": "off",
"no-eval": "error",
"no-fallthrough": "off",
"no-invalid-this": "off",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/on-push.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: vscode-lean build

on: [push]
on: [push, pull_request]

jobs:
build_job:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
out
node_modules
*.vsix
media/index.js
infoview/dist
11 changes: 11 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,24 @@
"version": "2.0.0",
"tasks": [
{
"label": "watch",
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": "build"
},
{
"label": "compile",
"type": "npm",
"script": "compile",
"problemMatcher": "$tsc",
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
Expand Down
1 change: 1 addition & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ src/**
.gitignore
tsconfig.json
vsc-extension-quickstart.md
node_modules
9 changes: 9 additions & 0 deletions infoview/custom.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// to get importing svg files to not error.
declare module '*.png' {
const content: any;
export default content;
}
declare module '*.svg' {
const attributes: any;
const content: string;
}
200 changes: 200 additions & 0 deletions infoview/event_model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import { Signal, SignalBuilder } from './util';
import { Event, CurrentTasksResponse, WidgetEventHandler, WidgetEventRequest, WidgetData, GoalState, Message } from 'lean-client-js-core'
import { global_server, ServerRestartEvent, ConfigEvent } from './server';
import {Location, locationKey,} from '../src/shared';
import { GetMessagesFor } from './messages';
import * as React from 'react';

function isLoading(ts: CurrentTasksResponse, l: Location) {
if (l === undefined) {return false; }
return ts.tasks.some(t => t.file_name === l.file_name && t.pos_line < l.line && l.line < t.end_pos_line);
}
function isDone(ts: CurrentTasksResponse) {
return ts.tasks.length === 0
}

/** Older versions of Lean can't deal with multiple simul info requests so this just prevents that. */
class OneAtATimeDispatcher {
inflight = 0;
head: Promise<any> = new Promise((r) => r({}));
constructor () {}
run<T>(tb: () => Promise<T>): Promise<T> {
if (this.inflight === 0) {
this.inflight++;
this.head = tb().finally(() => {this.inflight--;});
return this.head;
} else {
this.inflight++;
this.head = this.head
.catch(() => ({}))
.then(() => tb().finally(() => {this.inflight--;}));
return this.head;
}
}
}
const global_dispatcher = new OneAtATimeDispatcher();


interface WidgetEventArgs {
kind;
handler: WidgetEventHandler;
args;
}

export function infoEvents(sb: SignalBuilder, sinks: {onEdit}, onProps: Signal<InfoProps>): Signal<InfoState> {
const onForceUpdate = sb.mkEvent<any>();
const onWidgetEvent = sb.mkEvent<WidgetEventArgs>();
const state = sb.mkEvent<InfoState>();
const statev = sb.store(state);

const {loc: onLoc, isPaused: onPaused} = sb.unzip(onProps, ['loc', 'isPaused']);
sb.store(onLoc);
sb.store(onPaused);

const throttled_loc = sb.throttle<Location>(300, onLoc);
const onTasks = sb.throttle(300, global_server.tasks);
const onIsLoading = sb.map(({l, t}) => isLoading(t, l), sb.zip({l:throttled_loc, t:onTasks}));

const updateTrigger = sb.merge(sb.filter((x) => !onPaused.value, sb.merge(
ServerRestartEvent,
global_server.error,
sb.filter(x => !x, onPaused),
sb.onChange(onIsLoading),
sb.onChange(sb.map(isDone, onTasks)),
throttled_loc
)), onForceUpdate);

const onMessage = sb.map(({msgs, loc, config}) => {
return {messages: GetMessagesFor(msgs.msgs, loc, config)};
}, sb.zip({msgs: global_server.allMessages, loc: throttled_loc, config: ConfigEvent}));

const {result, isRunning} = sb.throttleTask<Location, Partial<InfoState>>(async () => {
const loc = onLoc.value;
if (!loc) {return {};}
try {
// [todo] if the location has not changed keep the widget and goal state?
const res: any = {widget: null, goalState: null, error: null};
const info = await global_dispatcher.run(() => global_server.info(loc.file_name, loc.line, loc.column));
const record = info.record;
res.goalState = record && record.state;
if (record && record.widget) {
if (record.widget.html !== undefined) {
res.widget = record.widget;
} else {
const { widget: newWidget } = await global_server.send({
command: 'get_widget',
line: record.widget.line,
column: record.widget.column,
id: record.widget.id,
file_name: loc.file_name,
});
res.widget = newWidget;
}
}
return res;
} catch (error) {
return {error};
}
}, updateTrigger);

const we = sb.mapTaskOrdered(async (e) => {
const s = statev.value;
if (!s) {return {}; }
if (!s.loc) {return {};}
if (!s.widget) {return {};}
const message: WidgetEventRequest = {
command: 'widget_event',
line: s.widget.line,
column: s.widget.column,
id: s.widget.id,
file_name: s.loc.file_name,
...e,
};
const update_result = await global_server.send(message);
if (!update_result.record) { return; }
const record = update_result.record;
if (record.status === 'success' && record.widget) {
return {widget: record.widget};
} else if (record.status === 'edit') {
sinks.onEdit(s.loc, record.action);
return {widget: record.widget};
} else if (record.status === 'invalid_handler') {
console.warn(`No widget_event update for ${message.handler}: invalid handler.`)
} else if (record.status === 'error') {
console.error(`Update gave an error: ${record.message || record}`);
}
}, onWidgetEvent);

const r: Signal<Partial<InfoState>> = sb.merge(
result,
sb.map<boolean, Partial<InfoState>>(l => ({isLoading:l}), sb.debounce(100, onIsLoading)),
sb.map<boolean, Partial<InfoState>>(l => ({isUpdating:l}), sb.debounce(100, isRunning)),
onProps,
we,
onMessage,
);

const defaultInfoProps: InfoState = {
isLoading: false,
isUpdating: false,
isPaused: false,
messages: [],
forceUpdate: () => onForceUpdate.fire({}),
handleWidgetEvent: (w) => onWidgetEvent.fire(w)
};
const z = sb.scan<InfoState,Partial<InfoState>>((acc, x) => ({...acc, ...x}), defaultInfoProps, r);
sb.push(z.on(x => state.fire(x)));
return state;
}

export interface InfoProps {
isPinned: boolean;
isCursor: boolean;
isPaused: boolean;
loc: Location;
}

export interface InfoSinks {
onEdit: (l: Location, text: string) => void;
onPin: (new_pin_state: boolean) => void;
setPaused: (paused: boolean) => void;
}

export interface InfoState {
loc?: Location;
isPaused: boolean;

isLoading: boolean;
isUpdating: boolean;
widget?: WidgetData;
goalState?: GoalState;
error?: {message: string};
messages: Message[];

forceUpdate: () => void;
handleWidgetEvent;
}

const defaultInfoState: InfoState = {
isLoading: false,
isUpdating: false,
isPaused: false,
messages: [],
forceUpdate: () => {},
handleWidgetEvent: () => {},
}

export function useInfo(ps: InfoProps, onEdit) {
const [g,s] = React.useState(defaultInfoState);
const pes = React.useRef<Event<InfoProps>>();
React.useEffect(() => {
const sb = new SignalBuilder();
pes.current = sb.mkEvent<InfoProps>();
sb.push(infoEvents(sb, {onEdit}, pes.current).on(s));
return () => sb.dispose();
}, []);
React.useEffect(() => {
pes.current.fire(ps);
}, [ps.isPaused, ps.loc && locationKey(ps.loc)]);
return g;
}
28 changes: 28 additions & 0 deletions infoview/goal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from 'react';
import { colorizeMessage, escapeHtml } from './util';
import { ConfigContext } from './index';

interface GoalProps {
goalState: string;
}

export function Goal(props: GoalProps): JSX.Element {
const config = React.useContext(ConfigContext);
if (!props.goalState) { return null; }
const reFilters = config.infoViewTacticStateFilters || [];
const filterIndex = config.filterIndex ?? -1;
let goalString = props.goalState.replace(/^(no goals)/mg, 'goals accomplished')
goalString = RegExp('^\\d+ goals|goals accomplished', 'mg').test(goalString) ? goalString : '1 goal\n'.concat(goalString);
if (!(reFilters.length === 0 || filterIndex === -1)) {
// this regex splits the goal state into (possibly multi-line) hypothesis and goal blocks
// by keeping indented lines with the most recent non-indented line
goalString = goalString.match(/(^(?! ).*\n?( .*\n?)*)/mg).map((line) => line.trim())
.filter((line) => {
const filt = reFilters[filterIndex];
const test = (new RegExp(filt.regex, filt.flags)).exec(line) !== null;
return filt.match ? test : !test;
}).join('\n');
}
goalString = colorizeMessage(escapeHtml(goalString));
return <pre className="font-code" style={{whiteSpace: 'pre-wrap'}} dangerouslySetInnerHTML={{ __html: goalString }} />
}
87 changes: 87 additions & 0 deletions infoview/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@

/* Some styles specific to the infoview. */

/* These are syntax highlights for the string goal view. */
.goal-goals { color: #569cd6; }
.goal-vdash { color: #569cd6; }
.goal-case { color: #a1df90; }
.goal-hyp { color: #ffcc00; }

.vscode-light .goal-goals { color: #367cb6; }
.vscode-light .goal-vdash { color: #367cb6; }
.vscode-light .goal-case { color: #1f7a1f; }
.vscode-light .goal-hyp { color: #cc7a00; }

.highlight { /* Used to denote text highlighted by the pretty-print expression widget. */
background-color: #96ccff;
}

.vscode-dark .highlight {
background-color: #569cd6;
}

.error {
color: darkred;
}

.warning {
color: darkorange;
}

.information {
color: darkgreen;
}

.vscode-dark .error {
color: red;
}

.vscode-dark .warning {
color: orange;
}

.vscode-dark .information {
color: lightgreen;
}

.vscode-high-contrast .error {
color: lightpink;
}

.vscode-high-contrast .warning {
color: yellow;
}

.vscode-high-contrast .information {
color: lightgreen;
}

/* Headers for infoview */

h1 {
display: block;
margin-bottom: 1ex;
margin-top: 1ex;
border-bottom: 1px solid;
padding: 0px;
font-weight: normal;
font-size: 100%;
}

.collapsible-header {
border-bottom-color: black;
}
.vscode-dark .collapsible-header {
border-bottom-color: lightgray;
}
.vscode-high-contrast .collapsible-header {
border-bottom-color: white;
}

@keyframes spinner {
to {transform: rotate(360deg);}
}

.spin {
animation: spinner .6s linear infinite;
}
Loading