Skip to content

Commit

Permalink
feat: finalize project info detection
Browse files Browse the repository at this point in the history
  • Loading branch information
ivangabriele committed Jul 15, 2023
1 parent 80e4fd1 commit 6a142a4
Show file tree
Hide file tree
Showing 28 changed files with 2,018 additions and 190 deletions.
4 changes: 3 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"rules": {
"no-console": ["warn", { "allow": ["error", "info", "warn"] }],

"import/no-extraneous-dependencies": "off"
"import/no-extraneous-dependencies": "off",

"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
}
}
5 changes: 4 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
"configurations": [
{
"name": "Run Extension",
"args": ["--extensionDevelopmentPath=${workspaceRoot}"],
"args": ["--disable-extensions", "--extensionDevelopmentPath=${workspaceRoot}"],
"env": {
"IS_DEBUG": "true"
},
"outFiles": ["${workspaceRoot}/build/**/*.js"],
"preLaunchTask": "${defaultBuildTask}",
"request": "launch",
Expand Down
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"tasks": [
{
"type": "npm",
"script": "watch",
"script": "build",
"group": {
"kind": "build",
"isDefault": true
Expand Down
1,554 changes: 1,554 additions & 0 deletions output.json

Large diffs are not rendered by default.

26 changes: 19 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
"main": "./dist/extension.js",
"scripts": {
"build": "rollup -c",
"bundle": "(rm -Rf *.vsix || true) && vsce package --yarn",
"bundle": "yarn clean && yarn build && (rm -Rf *.vsix || true) && vsce package --yarn",
"clean": "rm -Rf ./dist",
"release": "semantic-release && vsce publish --yarn",
"test:unit": "jest --config ./config/jest.config.js",
"watch": "yarn clean && yarn build"
"test:lint": "eslint .",
"test:type": "tsc --noEmit",
"test:unit": "jest --config ./config/jest.config.js"
},
"devDependencies": {
"@ivangabriele/eslint-config-typescript-base": "7.1.1",
Expand Down Expand Up @@ -47,6 +48,7 @@
"eslint-plugin-sort-destructure-keys": "1.5.0",
"eslint-plugin-sort-keys-fix": "1.1.2",
"eslint-plugin-typescript-sort-keys": "2.3.0",
"globby": "13.2.2",
"jest": "29.6.1",
"mocha": "10.2.0",
"prettier": "2.8.8",
Expand All @@ -70,11 +72,11 @@
"contributes": {
"commands": [
{
"command": "extension.openai-forge.addOrRemoveCurrentDocument",
"command": "openai-forge.addOrRemoveCurrentDocument",
"title": "OpenAI Forge: Add/Remove current document to/from the stack"
},
{
"command": "extension.openai-forge.sendCurrentDocument",
"command": "openai-forge.sendCurrentDocument",
"title": "OpenAI Forge: Send current document or documents stack"
}
],
Expand All @@ -90,14 +92,24 @@
},
"keybindings": [
{
"command": "extension.openai-forge.addOrRemoveCurrentDocument",
"command": "openai-forge.addOrRemoveCurrentDocument",
"key": "alt+f a",
"when": "editorTextFocus"
},
{
"command": "extension.openai-forge.sendCurrentDocument",
"command": "openai-forge.addOrRemoveCurrentDocument",
"key": "alt+f alt+a",
"when": "editorTextFocus"
},
{
"command": "openai-forge.sendCurrentDocument",
"key": "alt+f s",
"when": "editorTextFocus"
},
{
"command": "openai-forge.sendCurrentDocument",
"key": "alt+f alt+s",
"when": "editorTextFocus"
}
]
},
Expand Down
17 changes: 12 additions & 5 deletions src/commands/addOrRemoveCurrentDocument.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { DocumentInfo } from '../libs/DocumentInfo'
import { stackManager } from '../libs/stackManager'
import { getCurrentDocumentInfo } from '../utils/getCurrentDocumentInfo'
import { getCurrentDocumentPath } from '../utils/getCurrentDocumentPath'
import { updateStackStatusBarItem } from '../utils/updateStackStatusBarItem'

export function addOrRemoveCurrentDocument() {
const currentDocumentInfo = getCurrentDocumentInfo()
type AddOrRemoveCurrentDocumentArgs = {
absolutePath: string
}

export function addOrRemoveCurrentDocument(args?: AddOrRemoveCurrentDocumentArgs) {
const currentDocumentAbsolutePath = args ? args.absolutePath : getCurrentDocumentPath()

const isCurrentDocumentSelected = stackManager.documentInfos.some(
({ absolutePath }) => absolutePath === currentDocumentInfo.absolutePath,
({ absolutePath }) => absolutePath === currentDocumentAbsolutePath,
)

if (!isCurrentDocumentSelected) {
const currentDocumentInfo = new DocumentInfo()

stackManager.documentInfos = [...stackManager.documentInfos, currentDocumentInfo]
} else {
stackManager.documentInfos = stackManager.documentInfos.filter(
({ absolutePath }) => absolutePath !== currentDocumentInfo.absolutePath,
({ absolutePath }) => absolutePath !== currentDocumentAbsolutePath,
)
}

Expand Down
16 changes: 10 additions & 6 deletions src/commands/sendCurrentDocumentOrStack.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import { workspace } from 'vscode'

import { DocumentInfo } from '../libs/DocumentInfo'
import { stackManager } from '../libs/stackManager'
import { WebSocketDataAction, type WebSocketData } from '../types'
import { formatPrompt } from '../utils/formatPrompt'
import { getCurrentDocumentInfo } from '../utils/getCurrentDocumentInfo'
import { getCurrentWorkspaceInfo } from '../utils/getCurrentWorkspaceInfo'

import type { WebSocket } from 'ws'

export function sendCurrentDocument(webSocket: WebSocket) {
const currentWorkspaceInfo = getCurrentWorkspaceInfo()
export async function sendCurrentDocument(webSocket: WebSocket) {
const excludeProjectInfo = workspace.getConfiguration('openai-forge').get<boolean>('promt.excludeProjectInfo')

const currentWorkspaceInfo = !excludeProjectInfo ? await getCurrentWorkspaceInfo() : undefined
const currentOrStackDocumentInfos = stackManager.documentInfos.length
? stackManager.documentInfos
: [getCurrentDocumentInfo()]
: [new DocumentInfo()]

const promptMessage = formatPrompt(currentWorkspaceInfo, currentOrStackDocumentInfos)
const message = await formatPrompt(currentWorkspaceInfo, currentOrStackDocumentInfos)

const webSocketData: WebSocketData = {
action: WebSocketDataAction.ASK,
message: promptMessage,
message,
}

webSocket.send(JSON.stringify(webSocketData))
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { State } from './types'

export const STATE_ICON: Record<State, string> = {
[State.FAILED]: 'error',
[State.RUNNING]: 'radio-tower',
[State.STARTING]: 'gear-spin',
[State.STOPPED]: 'circle-slash',
[State.STOPPING]: 'gear-spin',
}

export const STATE_LABEL: Record<State, string> = {
[State.FAILED]: 'Failed',
[State.RUNNING]: '',
[State.STARTING]: 'Starting...',
[State.STOPPED]: 'Stopped',
Expand Down
36 changes: 22 additions & 14 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { type ExtensionContext, workspace, commands } from 'vscode'

import { addOrRemoveCurrentDocument } from './commands/addOrRemoveCurrentDocument'
import { sendCurrentDocument } from './commands/sendCurrentDocumentOrStack'
import { server } from './libs/server'
import { stateManager } from './libs/stateManager'
import { getCurrentWorkspaceInfo } from './utils/getCurrentWorkspaceInfo'
import { handleError } from './utils/handleError'
import { startWebSocketServer } from './utils/startWebSocketServer'
import { updateStackStatusBarItem } from './utils/updateStackStatusBarItem'
import { updateStateStatusBarItem } from './utils/updateStateStatusBarItem'

Expand All @@ -17,32 +18,39 @@ export async function activate(context: ExtensionContext) {
return
}

// -------------------------------------------------------------------------
// Status Bar Items

updateStateStatusBarItem()
updateStackStatusBarItem()

// -------------------------------------------------------------------------
// WebSocket Server

startWebSocketServer()

// -------------------------------------------------------------------------
// Commands

const addOrRemoveCurrentDocumentDisposable = commands.registerCommand(
'extension.openai-forge.addOrRemoveCurrentDocument',
'openai-forge.addOrRemoveCurrentDocument',
addOrRemoveCurrentDocument,
)
const sendCurrentDocumentDisposable = commands.registerCommand('extension.openai-forge.sendCurrentDocument', () => {
const sendCurrentDocumentDisposable = commands.registerCommand('openai-forge.sendCurrentDocument', () => {
stateManager.clients.forEach(sendCurrentDocument)
})

context.subscriptions.push(addOrRemoveCurrentDocumentDisposable)
context.subscriptions.push(sendCurrentDocumentDisposable)

// -------------------------------------------------------------------------
// Status Bar Items

updateStateStatusBarItem()
updateStackStatusBarItem()

// -------------------------------------------------------------------------
// WebSocket Server

server.start()

const workspaceInfo = await getCurrentWorkspaceInfo()

console.log(JSON.stringify(workspaceInfo, null, 2))

Check warning on line 48 in src/extension.ts

View workflow job for this annotation

GitHub Actions / Lint

Unexpected console statement

Check warning on line 48 in src/extension.ts

View workflow job for this annotation

GitHub Actions / Lint

Use undefined instead of null
} catch (err) {
handleError(err)

server.stop()
updateStackStatusBarItem(true)
}
}

Expand Down
41 changes: 41 additions & 0 deletions src/libs/DocumentInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import path from 'path'
import { Uri, window, workspace } from 'vscode'

import { InternalError } from './InternalError'
import { UserError } from './UserError'
import { getWorkspaceRootPath } from '../utils/getWorkspaceRootPath'

export class DocumentInfo {
#absolutePath: string
#relativePath: string

constructor() {
const editor = window.activeTextEditor
if (!editor) {
throw new UserError('No active text editor.')
}

const workspaceRootPath = getWorkspaceRootPath()

this.#absolutePath = editor.document.uri.fsPath
this.#relativePath = path.relative(workspaceRootPath, this.#absolutePath)
}

get absolutePath(): string {
return this.#absolutePath
}

get relativePath(): string {
return this.#relativePath
}

async getSource(): Promise<string> {
try {
const textDocument = await workspace.openTextDocument(Uri.file(this.absolutePath))

return textDocument.getText()
} catch (err) {
throw new InternalError(`Error reading document: ${this.absolutePath}`, err)
}
}
}
61 changes: 61 additions & 0 deletions src/libs/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { WebSocketServer } from 'ws'

import { InternalError } from './InternalError'
import { stateManager } from './stateManager'
import { State } from '../types'
import { updateStateStatusBarItem } from '../utils/updateStateStatusBarItem'

class Server {
#webSocketServer: WebSocketServer | undefined

start() {
try {
if (this.#webSocketServer) {
return
}

this.#webSocketServer = new WebSocketServer({ port: 4242 })

this.#webSocketServer.on('connection', webSocket => {
stateManager.clients.add(webSocket)
updateStateStatusBarItem()

// webSocket.on('message', message => {
// console.debug(`New message received: ${message}.`)
// })

webSocket.on('close', () => {
stateManager.clients.delete(webSocket)
updateStateStatusBarItem()
})
})

stateManager.state = State.RUNNING
updateStateStatusBarItem()
} catch (err) {
throw new InternalError('WebSocket server failed to start.', err)
}
}

stop() {
try {
if (!this.#webSocketServer) {
return
}

this.#webSocketServer.close(err => {
if (err) {
throw new InternalError('WebSocket server failed to stop.', err)
}

this.#webSocketServer = undefined
stateManager.state = State.STOPPED
updateStateStatusBarItem()
})
} catch (err) {
throw new InternalError('WebSocket server failed to stop.', err)
}
}
}

export const server = new Server()
2 changes: 1 addition & 1 deletion src/libs/stackManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DocumentInfo } from '../types'
import type { DocumentInfo } from './DocumentInfo'

class StackManager {
#documentInfos: DocumentInfo[] = []
Expand Down
Loading

0 comments on commit 6a142a4

Please sign in to comment.