-
-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: YASNCB (Yet Another Strict Null Checks Branch) #1703
base: dev
Are you sure you want to change the base?
Changes from 58 commits
aa2250b
a697c11
02d317d
02960ca
0f72124
9426650
c73129e
3dd6b85
6e6640f
5aad863
0510888
347e7eb
2527798
be6765b
46fa6ad
ff9f09d
6e17118
39c3208
e2622a2
7f77027
28cf0f3
25af9b9
4043c42
74ab8f9
6a04743
b91edb1
a58fbf1
30cc621
6e26d72
387326f
c8c7ee7
cb079b5
20d0f2c
1cddd85
49a0f0f
b9cdce3
d608036
b33def4
2dc2abf
407b589
5e2ed4b
6ff6e9b
e8c4cb1
b6b8db4
aea1267
c6fd333
8425e1a
c3735e3
1cdcd92
fcf14e0
adfe62a
b119164
5da7c79
ac8f195
c1417db
f310e64
859a6bb
7ac6f57
1e921d6
61437fe
d0cd19c
0778866
857054d
5106ee8
18d7761
3d1aec3
b83c26d
13d7e82
bc7fadd
cd0d893
6414e32
f5c1fbd
df16f82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ async function readJarContent(uri: string) { | |
} | ||
|
||
async function readRuntimeConfigs() { | ||
util.assertIsDefined(nClient, 'Expected there to be an nREPL client!'); | ||
const classpath = await nClient.session.classpath().catch((e) => { | ||
console.error('readRuntimeConfigs:', e); | ||
}); | ||
|
@@ -112,12 +113,9 @@ async function connectToHost(hostname: string, port: number, connectSequence: Re | |
|
||
if (connectSequence.afterCLJReplJackInCode) { | ||
outputWindow.append(`\n; Evaluating 'afterCLJReplJackInCode'`); | ||
await evaluateInOutputWindow( | ||
connectSequence.afterCLJReplJackInCode, | ||
'clj', | ||
outputWindow.getNs(), | ||
{} | ||
); | ||
const ns = outputWindow.getNs(); | ||
util.assertIsDefined(ns, 'Expected outputWindow to have a namespace!'); | ||
await evaluateInOutputWindow(connectSequence.afterCLJReplJackInCode, 'clj', ns, {}); | ||
} | ||
|
||
outputWindow.appendPrompt(); | ||
|
@@ -371,15 +369,23 @@ function createCLJSReplType( | |
'cljsReplTypeHasBuilds', | ||
cljsType.buildsRequired | ||
); | ||
let initCode = cljsType.connectCode, | ||
build: string = null; | ||
let initCode: typeof cljsType.connectCode | undefined = cljsType.connectCode, | ||
build: string | null = null; | ||
if (menuSelections && menuSelections.cljsDefaultBuild && useDefaultBuild) { | ||
build = menuSelections.cljsDefaultBuild; | ||
useDefaultBuild = false; | ||
} else { | ||
if (typeof initCode === 'object' || initCode.includes('%BUILD%')) { | ||
const buildsForSelection = startedBuilds | ||
? startedBuilds | ||
: await figwheelOrShadowBuilds(cljsTypeName); | ||
util.assertIsDefined( | ||
buildsForSelection, | ||
'Expected there to be figwheel or shadowcljs builds!' | ||
); | ||
|
||
build = await util.quickPickSingle({ | ||
values: startedBuilds ? startedBuilds : await figwheelOrShadowBuilds(cljsTypeName), | ||
values: buildsForSelection, | ||
placeHolder: 'Select which build to connect to', | ||
saveAs: `${state.getProjectRootUri().toString()}/${cljsTypeName.replace( | ||
' ', | ||
|
@@ -415,12 +421,10 @@ function createCLJSReplType( | |
); | ||
}, | ||
connected: (result, out, err) => { | ||
if (cljsType.isConnectedRegExp) { | ||
return ( | ||
[...out, result].find((x) => { | ||
return x.search(cljsType.isConnectedRegExp) >= 0; | ||
}) != undefined | ||
); | ||
const { isConnectedRegExp } = cljsType; | ||
|
||
if (isConnectedRegExp) { | ||
return [...out, result].find((x) => x.search(isConnectedRegExp) >= 0) !== undefined; | ||
} else { | ||
return true; | ||
} | ||
|
@@ -431,12 +435,15 @@ function createCLJSReplType( | |
replType.start = async (session, name, checkFn) => { | ||
let startCode = cljsType.startCode; | ||
if (!hasStarted) { | ||
util.assertIsDefined(startCode, 'Expected startCode to be defined!'); | ||
if (startCode.includes('%BUILDS')) { | ||
let builds: string[]; | ||
if (menuSelections && menuSelections.cljsLaunchBuilds) { | ||
builds = menuSelections.cljsLaunchBuilds; | ||
} else { | ||
const allBuilds = await figwheelOrShadowBuilds(cljsTypeName); | ||
util.assertIsDefined(allBuilds, 'Expected there to be figwheel or shadowcljs builds!'); | ||
|
||
builds = | ||
allBuilds.length <= 1 | ||
? allBuilds | ||
|
@@ -494,11 +501,11 @@ function createCLJSReplType( | |
} | ||
|
||
replType.started = (result, out, err) => { | ||
if (cljsType.isReadyToStartRegExp && !hasStarted) { | ||
const { isReadyToStartRegExp } = cljsType; | ||
|
||
if (isReadyToStartRegExp && !hasStarted) { | ||
const started = | ||
[...out, ...err].find((x) => { | ||
return x.search(cljsType.isReadyToStartRegExp) >= 0; | ||
}) != undefined; | ||
[...out, ...err].find((x) => x.search(isReadyToStartRegExp) >= 0) !== undefined; | ||
if (started) { | ||
hasStarted = true; | ||
} | ||
|
@@ -512,7 +519,7 @@ function createCLJSReplType( | |
return replType; | ||
} | ||
|
||
async function makeCljsSessionClone(session, repl: ReplType, projectTypeName: string) { | ||
async function makeCljsSessionClone(session, repl: ReplType, projectTypeName: string | undefined) { | ||
outputWindow.append('; Creating cljs repl session...'); | ||
let newCljsSession = await session.clone(); | ||
newCljsSession.replType = 'cljs'; | ||
|
@@ -521,7 +528,8 @@ async function makeCljsSessionClone(session, repl: ReplType, projectTypeName: st | |
outputWindow.append( | ||
'; The Calva Connection Log might have more connection progress information.' | ||
); | ||
if (repl.start != undefined) { | ||
if (repl.start !== undefined) { | ||
util.assertIsDefined(repl.started, "Expected repl to have a 'started' check function!"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Calls within |
||
if (await repl.start(newCljsSession, repl.name, repl.started)) { | ||
state.analytics().logEvent('REPL', 'StartedCLJS', repl.name).send(); | ||
outputWindow.append('; Cljs builds started'); | ||
|
@@ -534,6 +542,9 @@ async function makeCljsSessionClone(session, repl: ReplType, projectTypeName: st | |
return [null, null]; | ||
} | ||
} | ||
|
||
util.assertIsDefined(repl.connect, 'Expected repl to have a connect function!'); | ||
|
||
if (await repl.connect(newCljsSession, repl.name, repl.connected)) { | ||
state.analytics().logEvent('REPL', 'ConnectedCLJS', repl.name).send(); | ||
setStateValue('cljs', (cljsSession = newCljsSession)); | ||
|
@@ -588,7 +599,7 @@ async function promptForNreplUrlAndConnect(port, connectSequence: ReplConnectSeq | |
return true; | ||
} | ||
|
||
export let nClient: NReplClient; | ||
export let nClient: NReplClient | undefined; | ||
export let cljSession: NReplSession; | ||
export let cljsSession: NReplSession; | ||
|
||
|
@@ -637,7 +648,7 @@ export async function connect( | |
return true; | ||
} | ||
|
||
async function standaloneConnect(connectSequence: ReplConnectSequence) { | ||
async function standaloneConnect(connectSequence: ReplConnectSequence | undefined) { | ||
await outputWindow.initResultsDoc(); | ||
await outputWindow.openResultsDoc(); | ||
|
||
|
@@ -701,20 +712,21 @@ export default { | |
// the REPL client was connected. | ||
nClient.close(); | ||
} | ||
|
||
liveShareSupport.didDisconnectRepl(); | ||
nClient = undefined; | ||
} | ||
|
||
callback(); | ||
}, | ||
toggleCLJCSession: () => { | ||
let newSession: NReplSession; | ||
let newSession: NReplSession | undefined; | ||
|
||
if (getStateValue('connected')) { | ||
if (replSession.getSession('cljc') == replSession.getSession('cljs')) { | ||
newSession = replSession.getSession('clj'); | ||
} else if (replSession.getSession('cljc') == replSession.getSession('clj')) { | ||
newSession = replSession.getSession('cljs'); | ||
if (replSession.tryToGetSession('cljc') == replSession.tryToGetSession('cljs')) { | ||
newSession = replSession.tryToGetSession('clj'); | ||
} else if (replSession.tryToGetSession('cljc') == replSession.tryToGetSession('clj')) { | ||
newSession = replSession.tryToGetSession('cljs'); | ||
} | ||
setStateValue('cljc', newSession); | ||
if (outputWindow.isResultsDoc(util.getActiveTextEditor().document)) { | ||
|
@@ -726,9 +738,11 @@ export default { | |
} | ||
}, | ||
switchCljsBuild: async () => { | ||
const cljSession = replSession.getSession('clj'); | ||
const cljsTypeName: string = state.extensionContext.workspaceState.get('selectedCljsTypeName'), | ||
cljTypeName: string = state.extensionContext.workspaceState.get('selectedCljTypeName'); | ||
const cljSession = replSession.tryToGetSession('clj'); | ||
const cljsTypeName: string | undefined = | ||
state.extensionContext.workspaceState.get('selectedCljsTypeName'), | ||
cljTypeName: string | undefined = | ||
state.extensionContext.workspaceState.get('selectedCljTypeName'); | ||
state.analytics().logEvent('REPL', 'switchCljsBuild', cljsTypeName).send(); | ||
|
||
const [session, build] = await makeCljsSessionClone( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ const indentRules: IndentRules = { | |
*/ | ||
export interface IndentInformation { | ||
/** The first token in the expression (after the open paren/bracket etc.), as a raw string */ | ||
first: string; | ||
first: string | null; | ||
|
||
/** The indent immediately after the open paren/bracket etc */ | ||
startIndent: number; | ||
|
@@ -61,6 +61,17 @@ export function collectIndents( | |
let lastIndent = 0; | ||
const indents: IndentInformation[] = []; | ||
const rules = config['cljfmt-options']['indents']; | ||
const patterns = _.keys(rules); | ||
const regexpPatterns = patterns.reduce((regexpMap, pattern) => { | ||
const match = pattern.match(/^#"(.*)"$/); | ||
|
||
if (match) { | ||
regexpMap[pattern] = RegExp(match[1]); | ||
} | ||
|
||
return regexpMap; | ||
}, {} as Record<string, RegExp>); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I needed to fix some nulls here anyways so I took the chance to put into place some of the optimizations I mentioned in that other issue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there is some behaviour you think could get affected, add some unit tests for that. |
||
|
||
do { | ||
if (!cursor.backwardSexp()) { | ||
// this needs some work.. | ||
|
@@ -91,7 +102,10 @@ export function collectIndents( | |
|
||
const pattern = | ||
isList && | ||
_.find(_.keys(rules), (pattern) => pattern === token || testCljRe(pattern, token)); | ||
patterns.find( | ||
(pattern) => | ||
pattern === token || (regexpPatterns[pattern] && regexpPatterns[pattern].test(token)) | ||
); | ||
const indentRule = pattern ? rules[pattern] : []; | ||
indents.unshift({ | ||
first: token, | ||
|
@@ -138,11 +152,6 @@ export function collectIndents( | |
return indents; | ||
} | ||
|
||
const testCljRe = (re, str) => { | ||
const matches = re.match(/^#"(.*)"$/); | ||
return matches && RegExp(matches[1]).test(str); | ||
}; | ||
|
||
/** Returns the expected newline indent for the given position, in characters. */ | ||
export function getIndent(document: EditableModel, offset: number, config?: any): number { | ||
if (!config) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -155,12 +155,12 @@ export class LineInputModel implements EditableModel { | |
} | ||
return x; | ||
}) | ||
.filter((x) => x !== null) | ||
.filter((x) => x !== null) as number[] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TypeScript wasn't smart enough to know that filtering out nulls would make a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool. Thanks for mention I learn from them. ❤️ |
||
); | ||
|
||
this.insertedLines = new Set( | ||
Array.from(this.insertedLines) | ||
.map((x): [number, number] => { | ||
.map((x) => { | ||
const [a, b] = x; | ||
if (a > start && a < start + deleted) { | ||
return null; | ||
|
@@ -170,12 +170,12 @@ export class LineInputModel implements EditableModel { | |
} | ||
return [a, b]; | ||
}) | ||
.filter((x) => x !== null) | ||
.filter((x) => x !== null) as [number, number][] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same reasoning as above. |
||
); | ||
|
||
this.deletedLines = new Set( | ||
Array.from(this.deletedLines) | ||
.map((x): [number, number] => { | ||
.map((x) => { | ||
const [a, b] = x; | ||
if (a > start && a < start + deleted) { | ||
return null; | ||
|
@@ -185,7 +185,7 @@ export class LineInputModel implements EditableModel { | |
} | ||
return [a, b]; | ||
}) | ||
.filter((x) => x !== null) | ||
.filter((x) => x !== null) as [number, number][] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same same. |
||
); | ||
} | ||
|
||
|
@@ -224,7 +224,7 @@ export class LineInputModel implements EditableModel { | |
const seen = new Set<number>(); | ||
this.dirtyLines.sort(); | ||
while (this.dirtyLines.length) { | ||
let nextIdx = this.dirtyLines.shift(); | ||
let nextIdx = this.dirtyLines.shift() as number; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, TypeScript isn't smart enough to figure out that the length check on the previous line means this will never be undefined and will always be a number. |
||
if (seen.has(nextIdx)) { | ||
continue; | ||
} // already processed. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I stopped and wondered if we somehow consider the current selection here. Maybe name it
builds
? OrbuildCandidates
?.