Skip to content

Commit e2bd430

Browse files
committed
Enhance VSCode extension with inline editing capabilities and LLM integration; refactor code structure and improve configuration handling
1 parent 3f45ac8 commit e2bd430

File tree

13 files changed

+314
-123
lines changed

13 files changed

+314
-123
lines changed

build.sbt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ lazy val root = project
2222
scalaVersion := "3.3.4",
2323
// warn unused imports and vars
2424
scalacOptions ++= Seq(
25-
"-Wunused:all"
25+
"-Wunused:all",
26+
"-no-indent"
2627
),
2728
// check if it is running in test
2829
// testOptions += Tests.Setup(_ => sys.props("testing") = "true"),
@@ -80,8 +81,10 @@ def openVSCodeTask(openVscode: Boolean = true): Def.Initialize[Task[Unit]] =
8081
}
8182
// launch vscode
8283
if (openVscode) {
84+
val extenPath = s"${path}/${outdir}"
8385
println("\u001b[33m" + "[opening] vscode" + "\u001b[0m")
84-
s"code --extensionDevelopmentPath=$path" ! log
86+
println("\u001b[33m" + s"with extensionDevelopmentPath=${extenPath}" + "\u001b[0m")
87+
s"code --extensionDevelopmentPath=$extenPath" ! log
8588
}
8689
()
8790
}
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,43 @@
11
package functorcoder.actions
2+
import scala.concurrent.ExecutionContext.Implicits.global
23

34
import typings.vscode.mod as vscode
45

56
import scala.collection.immutable
67
import scala.scalajs.js
78

89
import vscextension.quickPick
10+
import vscextension.facade.vscodeUtils.showMessageAndLog
11+
import scala.concurrent.Future
12+
import functorcoder.types.editorCtx.codeActionParam
913

1014
/** Commands are actions that a user can invoke in the vscode extension with command palette (ctrl+shift+p).
1115
*/
1216
object Commands {
1317
type CommandT = Any => Unit
1418
// all the commands here
1519
val commandMenu = "functorcoder.menu"
20+
val commandAddDocumentation = "functorcoder.addDocumentation"
1621

1722
val commandList: Seq[(String, CommandT)] =
1823
Seq(
19-
(commandMenu, quickPick.showQuickPick)
24+
(commandMenu, quickPick.showQuickPick),
25+
(commandAddDocumentation, addDocumentation)
2026
)
2127

2228
// the main menu items
2329
val mainMenuItems: Seq[(String, () => Unit)] = Seq(
2430
"create files" -> { () => println("create files") }
2531
)
32+
33+
def addDocumentation(arg: Any) = {
34+
val param =
35+
arg.asInstanceOf[codeActionParam[Future[String]]]
36+
val llmResponse = param.param
37+
llmResponse.foreach { response =>
38+
showMessageAndLog("add doc: " + s"${param.documentUri}, ${param.range}, ${response}")
39+
}
40+
41+
// showMessageAndLog("add documentation: " + s"${dyn.uri}, ${dyn.range}, ${dyn.llmResponse}")
42+
}
2643
}

src/main/scala/functorcoder/editorUI/diffEdit.scala

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package functorcoder.editorUI
22

3+
import scala.concurrent.ExecutionContext.Implicits.global
4+
5+
import functorcoder.llm.llmMain
6+
import functorcoder.llm.llmPrompt
7+
38
/** This abstract the editor behavior for inline editing
49
*
5-
* Scenario: A new version of the file is shown to the user in the editor with the changes highlighted,
6-
*
7-
* and the user can choose to accept or reject the changes.
10+
* Scenario: user wants to edit a selected snippet of code in the editor, the coding assistant will provide a modified
11+
* version of the snippet with the changes highlighted, and the user can choose to accept or reject the changes.
812
*/
913
object diffEdit {
1014

@@ -13,6 +17,12 @@ object diffEdit {
1317
character: Int
1418
)
1519

20+
case class DiffRequest(
21+
oldText: String,
22+
cursorPosition: CursorPosition,
23+
task: String // the task to perform
24+
)
25+
1626
/** The result of the diff operation
1727
*
1828
* @param oldText
@@ -27,7 +37,33 @@ object diffEdit {
2737
case class DiffResult(
2838
oldText: String,
2939
newText: String,
30-
cursorPosition: CursorPosition,
31-
difference: Seq[String]
40+
cursorPosition: CursorPosition
41+
// difference: Seq[String]
3242
)
43+
44+
/** action to modify the code, like adding new code
45+
*
46+
* @param llmAgent
47+
* the agent to perform the diff operation
48+
* @param diffReq
49+
* the diff request
50+
* @return
51+
* the result of the diff operation
52+
*/
53+
def diff(llmAgent: llmMain.llmAgent, diffReq: DiffRequest) = {
54+
val prompt = llmPrompt.Modification(
55+
code = diffReq.oldText,
56+
taskRequirement = ""
57+
)
58+
59+
val llmResponse = llmAgent.sendPrompt(prompt)
60+
61+
llmResponse.map(txt =>
62+
DiffResult(
63+
oldText = diffReq.oldText,
64+
newText = txt,
65+
cursorPosition = diffReq.cursorPosition
66+
)
67+
)
68+
}
3369
}

src/main/scala/functorcoder/llm/llmMain.scala

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import scala.scalajs.js.Thenable.Implicits.*
1212
import scala.concurrent.Future
1313

1414
import functorcoder.editorUI.editorConfig
15+
import cats.syntax.show
1516

1617
/** large language model (LLM) AI main
1718
*
@@ -27,16 +28,21 @@ object llmMain {
2728
* completion prompt object
2829
* @return
2930
*/
30-
def getCompletionPrompt(completionPrompt: llmPrompt.Completion) = {
31-
openaiReq
31+
def prompt2str(inputPrompt: llmPrompt.Prompt) = {
32+
showMessageAndLog(s"prompt: ${inputPrompt}")
33+
showMessageAndLog(s"prompt assistant: ${inputPrompt.getAssistantMessage}")
34+
35+
val openAiRequest = openaiReq
3236
.OpenAiRequest(
3337
List(
34-
openaiReq.Message(roles.user, completionPrompt.codeWithHole),
35-
openaiReq.Message(roles.system, completionPrompt.assistantMessage)
38+
openaiReq.Message(roles.user, inputPrompt.generatePrompt),
39+
openaiReq.Message(roles.system, inputPrompt.getAssistantMessage)
3640
),
3741
openaiReq.models.gpt4o
3842
)
39-
.toJson
43+
44+
showMessageAndLog(s"openai request: ${openAiRequest}")
45+
openAiRequest.toJson
4046
}
4147

4248
case class llmAgent(editorCfg: editorConfig.Config) {
@@ -51,10 +57,10 @@ object llmMain {
5157
*
5258
* so we will call this function with the hole "{{FILL_HERE}}" you insert it in the code
5359
*/
54-
def getCodeCompletion(holeToCode: String => String) = {
55-
val requestStr = getCompletionPrompt(
56-
llmPrompt
57-
.Completion(holeToCode("{{FILL_HERE}}"))
60+
def sendPrompt(input: llmPrompt.Prompt) = {
61+
62+
val requestStr = prompt2str(
63+
input
5864
)
5965

6066
val requestOptions = getRequestOptions(requestStr)
@@ -76,6 +82,15 @@ object llmMain {
7682
}
7783
}
7884

85+
/** get the response text from ai api, only the content of the first choice
86+
*
87+
* it parses the response json and returns the first choice
88+
*
89+
* @param responseFuture
90+
* the response future
91+
* @return
92+
* the response text
93+
*/
7994
private def getResponseText(responseFuture: Future[nodeFetch.Response]) = {
8095
for {
8196
res <- responseFuture

src/main/scala/functorcoder/llm/llmPrompt.scala

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ package functorcoder.llm
55
* for completion, code generation, etc.
66
*/
77
object llmPrompt {
8+
// trait will have undefined value
9+
sealed abstract class Prompt(val assistantMsg: String) {
10+
def generatePrompt: String
11+
def getAssistantMessage: String = assistantMsg
12+
}
813

9-
/** a configuration for code completion
14+
/** code completion prompt
1015
*
1116
* https://github.com/continuedev/continue/blob/main/core/autocomplete/templating/AutocompleteTemplate.ts
1217
*
@@ -26,8 +31,8 @@ object llmPrompt {
2631
case class Completion(
2732
codeWithHole: String, // code with a hole to fill like {{FILL_HERE}}
2833
// taskRequirement: String, // like "Fill the {{FILL_HERE}} hole."
29-
assistantMessage: String = prompts.prompt1
30-
) {
34+
assistantMessage: String = promptText.prompt1
35+
) extends Prompt(assistantMessage) {
3136
def generatePrompt = {
3237
// shall return a string wrapped with <COMPLETION></COMPLETION>
3338
// s"""<QUERY>
@@ -40,13 +45,38 @@ object llmPrompt {
4045
*/
4146
codeWithHole
4247
}
48+
49+
}
50+
51+
/** modify code snippet
52+
*
53+
* @param code
54+
* code snippet
55+
* @param taskRequirement
56+
* like "Fill the {{FILL_HERE}} hole."
57+
* @param assistantMessage
58+
* like "always give scala code examples."
59+
*/
60+
case class Modification(
61+
code: String,
62+
taskRequirement: String,
63+
assistantMessage: String = promptText.promptTask
64+
) extends Prompt(assistantMessage) {
65+
def generatePrompt = {
66+
s"""<QUERY>
67+
|${code}
68+
|</QUERY>
69+
|TASK: ${taskRequirement}
70+
|""".stripMargin
71+
}
4372
}
4473

4574
/** prompts engineering
4675
*
4776
* more like art than science. just try different prompts and see what works best
4877
*/
49-
object prompts {
78+
object promptText {
79+
val hole = "{{FILL_HERE}}"
5080
val prompt1 =
5181
"You are a code or text autocompletion assistant. " +
5282
"In the provided input, missing code or text are marked as '{{FILL_HERE}}'. " +
@@ -58,11 +88,15 @@ object llmPrompt {
5888
"{{FILL_HERE}} in the string, " +
5989
"your task is to replace this hole with your reply." +
6090
"you only return the string for the hole with indentation, without any quotes"
91+
92+
val promptTask =
93+
"You are given a text or code snippet wrapped in a <QUERY> tag and a TASK requirement. " +
94+
"You are going to return the new snippet according to the TASK requirement. "
6195
}
6296
}
6397

6498
/* example:
65-
<QUERY>
99+
<QUERY>
66100
function sum_evens(lim) {
67101
var sum = 0;
68102
for (var i = 0; i < lim; ++i) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import functorcoder.llm.llmPrompt
2+
import functorcoder.llm.llmPrompt.Prompt
3+
import fansi.Str
4+
val Modification = llmPrompt
5+
.Modification(code = "val x = 1", taskRequirement = "add documentation")
6+
7+
Modification.asInstanceOf[Prompt]
8+
9+
sealed trait trait1(val param1: String) {
10+
// def method1: String = param1
11+
}
12+
13+
case class class1(override val param1: String = "s1") extends trait1(param1)
14+
15+
val c1 = class1()
16+
17+
def m1(t1: trait1) = {
18+
println(s"t1 param1: ${t1.param1}")
19+
}
20+
// c1.method1

src/main/scala/functorcoder/types/editorCtx.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
package functorcoder.types
2+
import scala.scalajs.js
23

34
object editorCtx {
45

@@ -10,4 +11,10 @@ object editorCtx {
1011
case class EditorContext(
1112
language: String
1213
)
14+
15+
class codeActionParam[T](
16+
val documentUri: String, //
17+
val range: typings.vscode.mod.Selection,
18+
val param: T
19+
) extends js.Object
1320
}

0 commit comments

Comments
 (0)