-
Notifications
You must be signed in to change notification settings - Fork 653
execute command line initial implementation #241
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
Conversation
internal/execute/system.go
Outdated
} | ||
|
||
func (s *osSys) EndWrite() { | ||
// do nothing, this is needed in the interface for testing |
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'm curious, when is this called? Is it a flushing operation? Something else?
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.
Every occurrence of "write" is tracked in the original code for several reasons, and the tracking is most used probably with screen clears (which seem mostly relevant in watch?) The reason why this is needed is because the old code implemented write
to be a separate entry each time we called write
. However, because we are using stringwriters in diagnostic outputting, and we could be passing the writers through fmt.fprint..
, several times in each diagnostic writing function, without an endwrite()
, writing in the test system generates different output based on if it's implemented as
fmt.fprint(sys, "Output::")
fmt.fprint(sys, errors)
fmt.fprint(sys, "\n")
vs
fmt.fprint(sys, "Output::" + errors + "\n")
and i don't see an easier way to make them the same atm. I hope to be able to simplify it eventually, but I don't want to make too many changes when watch isn't implemented yet, since that's the part where "each write" is tracked.
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.
That makes sense, though it seems like the assertion doesn't have to be per write, but it could be the entire output string buffered, right?
But, I can understand not wanting to mess with it for a port.
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'll continue to take a look at your buffer suggestion as I port/see what testing looks like after i finish adding tsconfig parsing to tests right now
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 would like this to be a TODO for a later PR since I would like testing to not be the priority for this PR
// todo: revisit if improving tsc/build/watch unittest baselines | ||
s.output = append(s.output, s.currentWrite.String()) |
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.
Couldn't we just write all output to a bytes.Buffer
or something, and then check it there? Checking line-based output seems like a lot of work.
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.
…o executeCommandLine
…o executeCommandLine
…o executeCommandLine
internal/compiler/host.go
Outdated
@@ -11,6 +11,7 @@ import ( | |||
|
|||
type CompilerHost interface { | |||
FS() vfs.FS | |||
SetOptions(options *core.CompilerOptions) |
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 suspect this isn't required; seems odd for the host to have a setter when that's the opposite direction of the flow of data...
(I think you have a comment of the sort in another file now that I read)
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.
Hm, but the host does acutally have it for other things. Makes me think the existing code isn't quite right.
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.
Makes me think that the existing code isn't quite right
Which existing code? I often had a hard time deciding which things should belong to which interface, so it's pretty possible that I'm just confused, and also possible that the implementer of existing code also wasn't sure how things would shake out in the future/also was confused.
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 mean the existing code implements hosts with methods that depends on options, which implies the host can answer questions about a config that hasn't even been set yet.
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.
oh yeah, it hits a lot of nil
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.
Eventually for things like watch, the options would need to propagate back up to the host. It seems to make enough sense to me?
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.
That feels a bit like a recipe for weird races / behavior, or confusing behavior if we want to share the host between multiple Program
s... If we're saying this thing is created by Program
for it to use, then I'm less afraid of it, but the way I'm reading it right now is that we are constructing one with NewCompilerHost
to give to a Program
.
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.
For watch mode, I would expect us to take one program, then use it to construct another program, which would involve giving it the last program's info, not reusing the same host object with mutable state...
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 see what you mean. I think the confusion comes from strada having compilerOptions
be a one-and-all object to hold everything, and at each level, not every option is used. For example, incremental
is only used in executeCommandLine
and emitter
, and I'm pretty sure that the separate watchOptions
object gets combined into the compilerOptions
object at some points, but because the watchoptions aren't used in places like checker, we don't really see that.
So the CompilerHost
would only need a subset of compilerOptions
, and Program
would need some overlapping subset. Since my implementation here has the parsed options being passed into the Program creation, that part for Program should be fine? 🤔
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.
On the other hand, it might be wrong to reset CompilerHost.options
during program creation 🤔, but I'm not sure that at this state we could tell, since we're only doing the config parsing once
(As far as I can tell, if I comment that line out, there's no difference in behavior atm)
internal/compiler/program.go
Outdated
// todo: remove/edit setOptions call if compilerHost no longer has CompilerOptions. Since compilerHost was created before options were parsed, compiler host would | ||
// not have options yet |
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.
Yeah, this sort of split feels weird.
…o executeCommandLine
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.
@navya9singh generally, I'm not sure if I'm missing places if I'm setting/saving the parsed compiler options or doing path handling for tsconfigparsing correctlu
tsConfigSourceFile := tsoptions.NewTsconfigSourceFileFromFilePath(configFileName, configFileText) | ||
cwd := sys.Host().GetCurrentDirectory() | ||
tsConfigSourceFile.SourceFile.SetPath(tspath.ToPath(configFileName, cwd, sys.FS().UseCaseSensitiveFileNames())) | ||
// tsConfigSourceFile.resolvedPath = tsConfigSourceFile.FileName() |
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.
@navya9singh are these fields are needed?
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 believe they are when files are included through project references. @jakebailey ?
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 don't really know off the top of my head, but that sounds plausible.
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 mostly only had questions, nothing looked too weird to me that wasn't weird in TS already.
}).verify(t) | ||
} | ||
|
||
// func TestExtends(t *testing.T) { |
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.
Might be good to add a todo comment here saying we can run those tests when we have support for extends
.
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 thought we already supported extends? vscode and the compiler are working.
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.
These tests run into nilpointer errors. I think it may be an issue with path handling that wasn't evident in the tsconfigparsing
tests for extends
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.
Right, but extends doesn't have the exception when run via tsgo
, so it feels odd for it to fail...
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.
On the same test cases?
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.
No, just on vscode and src/compiler; obviously not representative but I was just hoping this could run with some skips on specific tests or something. It's not a big deal, when I left my comment first I thought this was just accidentally commented out from before we supported it.
internal/compiler/program.go
Outdated
func (p *Program) GetOptionsDiagnostics() []*ast.Diagnostic { | ||
return p.optionsDiagnostics | ||
} | ||
func (p *Program) SourceFiles() []*ast.SourceFile { return p.files } |
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.
Not about this PR, but: why does compiler host have compiler options in the first place?
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 see there's a discussion on this elsewhere. I also agree it's weird.
}).verify(t) | ||
} | ||
|
||
// func TestExtends(t *testing.T) { |
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 thought we already supported extends? vscode and the compiler are working.
tsConfigSourceFile := tsoptions.NewTsconfigSourceFileFromFilePath(configFileName, configFileText) | ||
cwd := sys.Host().GetCurrentDirectory() | ||
tsConfigSourceFile.SourceFile.SetPath(tspath.ToPath(configFileName, cwd, sys.FS().UseCaseSensitiveFileNames())) | ||
// tsConfigSourceFile.resolvedPath = tsConfigSourceFile.FileName() |
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 believe they are when files are included through project references. @jakebailey ?
Co-authored-by: Jake Bailey <[email protected]>
…o executeCommandLine
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.
Just nits.
Co-authored-by: Jake Bailey <[email protected]>
tsc
can be invoked by writingtsc
as the second position, for exampleWithout
tsc
in the second position, there is no change totsgo
flag parsing/executionToDos for after this PR:
Things that are not yet implemented:
showConfig
,help
,version
, are not implementedPossible places for refactors:
System
vsHost
vsProgram
layering: discussion, commentSystem
vsHost
vsProgram
layering #272Testing
extends
nilpointer crash inexecuteCommandLine
#271