-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2a3a405
commit bda1046
Showing
10 changed files
with
1,416 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
*.zip | ||
PowerShellEditorServices/ | ||
.pses | ||
node_modules | ||
out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* -------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
* ------------------------------------------------------------------------------------------ */ | ||
'use strict'; | ||
|
||
import * as path from 'path'; | ||
import { workspace, ExtensionContext, commands, StatusBarItem } from 'coc.nvim'; | ||
import { TerminalResult } from 'coc.nvim/lib/types'; | ||
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'coc.nvim'; | ||
import { Range } from 'vscode-languageserver-types'; | ||
import { getDefaultPowerShellPath, getPlatformDetails } from './platform'; | ||
|
||
export function activate(context: ExtensionContext) { | ||
|
||
const pwshPath = getDefaultPowerShellPath(getPlatformDetails()) | ||
|
||
|
||
let serverOptions: ServerOptions = { | ||
command: pwshPath, | ||
args: [ | ||
"-NoProfile", | ||
"-NonInteractive", | ||
"/Users/tyler/Code/PowerShell/coc-powershell/PowerShellEditorServices/PowerShellEditorServices/Start-EditorServices.ps1", | ||
"-HostName", "coc.vim", | ||
"-HostProfileId", "0", | ||
"-HostVersion", "2.0.0", | ||
"-LogPath", "/Users/tyler/Code/PowerShell/coc-powershell/.pses/logs/1234/log.txt", | ||
"-LogLevel", "Diagnostic", | ||
"-FeatureFlags", "[]", | ||
"-BundledModulesPath", "/Users/tyler/Code/PowerShell/coc-powershell/PowerShellEditorServices/", | ||
"-Stdio", | ||
"-SessionDetailsPath", "/Users/tyler/Code/PowerShell/coc-powershell/.pses/logs/1234/session"], | ||
transport: TransportKind.stdio | ||
} | ||
|
||
workspace.addRootPatterns('powershell', ['*.ps1', '*.psd1', '*.psm1', '.vim', '.git', '.hg']) | ||
|
||
// Options to control the language client | ||
let clientOptions: LanguageClientOptions = { | ||
// Register the server for F# documents | ||
documentSelector: [{scheme: 'file', language: 'powershell'}], | ||
synchronize: { | ||
// Synchronize the setting section 'powershell' to the server | ||
configurationSection: 'powershell', | ||
// Notify the server about file changes to PowerShell files contain in the workspace | ||
// TODO: is there a way to configure this via the language server protocol? | ||
fileEvents: [ | ||
workspace.createFileSystemWatcher('**/*.ps1'), | ||
workspace.createFileSystemWatcher('**/*.psd1'), | ||
workspace.createFileSystemWatcher('**/*.psm1') | ||
] | ||
} | ||
} | ||
|
||
// Create the language client and start the client. | ||
let client = new LanguageClient('powershell', 'PowerShell Language Server', serverOptions, clientOptions); | ||
let disposable = client.start(); | ||
|
||
// Push the disposable to the context's subscriptions so that the | ||
// client can be deactivated on extension deactivation | ||
context.subscriptions.push(disposable); | ||
commands.registerCommand('powershell.command.goto', goto); | ||
} | ||
|
||
function goto(file: string, startLine: number, startColumn: number, _endLine: number, _endColumn: number) { | ||
let selection = Range.create(startLine, startColumn, startLine, startColumn); | ||
workspace.jumpTo(file, selection.start); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
/*--------------------------------------------------------- | ||
* Copyright (C) Microsoft Corporation. All rights reserved. | ||
*--------------------------------------------------------*/ | ||
|
||
import fs = require("fs"); | ||
import path = require("path"); | ||
import process = require("process"); | ||
import Settings = require("./settings"); | ||
|
||
const linuxExePath = "/usr/bin/pwsh"; | ||
const linuxPreviewExePath = "/usr/bin/pwsh-preview"; | ||
|
||
const snapExePath = "/snap/bin/pwsh"; | ||
const snapPreviewExePath = "/snap/bin/pwsh-preview"; | ||
|
||
const macOSExePath = "/usr/local/bin/pwsh"; | ||
const macOSPreviewExePath = "/usr/local/bin/pwsh-preview"; | ||
|
||
export enum OperatingSystem { | ||
Unknown, | ||
Windows, | ||
MacOS, | ||
Linux, | ||
} | ||
|
||
export interface IPlatformDetails { | ||
operatingSystem: OperatingSystem; | ||
isOS64Bit: boolean; | ||
isProcess64Bit: boolean; | ||
} | ||
|
||
export interface IPowerShellExeDetails { | ||
versionName: string; | ||
exePath: string; | ||
} | ||
|
||
export function getPlatformDetails(): IPlatformDetails { | ||
let operatingSystem = OperatingSystem.Unknown; | ||
|
||
if (process.platform === "win32") { | ||
operatingSystem = OperatingSystem.Windows; | ||
} else if (process.platform === "darwin") { | ||
operatingSystem = OperatingSystem.MacOS; | ||
} else if (process.platform === "linux") { | ||
operatingSystem = OperatingSystem.Linux; | ||
} | ||
|
||
const isProcess64Bit = process.arch === "x64"; | ||
|
||
return { | ||
operatingSystem, | ||
isOS64Bit: isProcess64Bit || process.env.hasOwnProperty("PROCESSOR_ARCHITEW6432"), | ||
isProcess64Bit, | ||
}; | ||
} | ||
|
||
/** | ||
* Gets the default instance of PowerShell for the specified platform. | ||
* On Windows, the default version of PowerShell is "Windows PowerShell". | ||
* @param platformDetails Specifies information about the platform - primarily the operating system. | ||
* @param use32Bit On Windows, this boolean determines whether the 32-bit version of Windows PowerShell is returned. | ||
* @returns A string containing the path of the default version of PowerShell. | ||
*/ | ||
export function getDefaultPowerShellPath( | ||
platformDetails: IPlatformDetails, | ||
use32Bit: boolean = false): string | null { | ||
|
||
let powerShellExePath; | ||
|
||
// Find the path to powershell.exe based on the current platform | ||
// and the user's desire to run the x86 version of PowerShell | ||
if (platformDetails.operatingSystem === OperatingSystem.Windows) { | ||
if (use32Bit) { | ||
powerShellExePath = | ||
platformDetails.isOS64Bit && platformDetails.isProcess64Bit | ||
? SysWow64PowerShellPath | ||
: System32PowerShellPath; | ||
} else { | ||
powerShellExePath = | ||
!platformDetails.isOS64Bit || platformDetails.isProcess64Bit | ||
? System32PowerShellPath | ||
: SysnativePowerShellPath; | ||
} | ||
} else if (platformDetails.operatingSystem === OperatingSystem.MacOS) { | ||
// Always default to the stable version of PowerShell (if installed) but handle case of only Preview installed | ||
powerShellExePath = macOSExePath; | ||
if (!fs.existsSync(macOSExePath) && fs.existsSync(macOSPreviewExePath)) { | ||
powerShellExePath = macOSPreviewExePath; | ||
} | ||
} else if (platformDetails.operatingSystem === OperatingSystem.Linux) { | ||
// Always default to the stable version of PowerShell (if installed) but handle case of only Preview installed | ||
// as well as the Snaps case - https://snapcraft.io/ | ||
powerShellExePath = linuxExePath; | ||
if (!fs.existsSync(linuxExePath) && fs.existsSync(linuxPreviewExePath)) { | ||
powerShellExePath = linuxPreviewExePath; | ||
} else if (fs.existsSync(snapExePath)) { | ||
powerShellExePath = snapExePath; | ||
} else if (fs.existsSync(snapPreviewExePath)) { | ||
powerShellExePath = snapPreviewExePath; | ||
} | ||
} | ||
|
||
return powerShellExePath; | ||
} | ||
|
||
export function getWindowsSystemPowerShellPath(systemFolderName: string) { | ||
return `${process.env.windir}\\${systemFolderName}\\WindowsPowerShell\\v1.0\\powershell.exe`; | ||
} | ||
|
||
export const System32PowerShellPath = getWindowsSystemPowerShellPath("System32"); | ||
export const SysnativePowerShellPath = getWindowsSystemPowerShellPath("Sysnative"); | ||
export const SysWow64PowerShellPath = getWindowsSystemPowerShellPath("SysWow64"); | ||
|
||
export const WindowsPowerShell64BitLabel = "Windows PowerShell (x64)"; | ||
export const WindowsPowerShell32BitLabel = "Windows PowerShell (x86)"; | ||
|
||
const powerShell64BitPathOn32Bit = SysnativePowerShellPath.toLocaleLowerCase(); | ||
const powerShell32BitPathOn64Bit = SysWow64PowerShellPath.toLocaleLowerCase(); | ||
|
||
export function fixWindowsPowerShellPath(powerShellExePath: string, platformDetails: IPlatformDetails): string { | ||
const lowerCasedPath = powerShellExePath.toLocaleLowerCase(); | ||
|
||
if ((platformDetails.isProcess64Bit && (lowerCasedPath === powerShell64BitPathOn32Bit)) || | ||
(!platformDetails.isProcess64Bit && (lowerCasedPath === powerShell32BitPathOn64Bit))) { | ||
return System32PowerShellPath; | ||
} | ||
|
||
// If the path doesn't need to be fixed, return the original | ||
return powerShellExePath; | ||
} | ||
|
||
/** | ||
* Gets a list of all available PowerShell instance on the specified platform. | ||
* @param platformDetails Specifies information about the platform - primarily the operating system. | ||
* @param sessionSettings Specifies the user/workspace settings. Additional PowerShell exe paths loaded from settings. | ||
* @returns An array of IPowerShellExeDetails objects with the PowerShell name & exe path for each instance found. | ||
*/ | ||
export function getAvailablePowerShellExes( | ||
platformDetails: IPlatformDetails, | ||
sessionSettings: Settings.ISettings | undefined): IPowerShellExeDetails[] { | ||
|
||
let paths: IPowerShellExeDetails[] = []; | ||
|
||
if (platformDetails.operatingSystem === OperatingSystem.Windows) { | ||
if (platformDetails.isProcess64Bit) { | ||
paths.push({ | ||
versionName: WindowsPowerShell64BitLabel, | ||
exePath: System32PowerShellPath, | ||
}); | ||
|
||
paths.push({ | ||
versionName: WindowsPowerShell32BitLabel, | ||
exePath: SysWow64PowerShellPath, | ||
}); | ||
} else { | ||
if (platformDetails.isOS64Bit) { | ||
paths.push({ | ||
versionName: WindowsPowerShell64BitLabel, | ||
exePath: SysnativePowerShellPath, | ||
}); | ||
} | ||
|
||
paths.push({ | ||
versionName: WindowsPowerShell32BitLabel, | ||
exePath: System32PowerShellPath, | ||
}); | ||
} | ||
|
||
const psCoreInstallPath = | ||
(!platformDetails.isProcess64Bit ? process.env.ProgramW6432 : process.env.ProgramFiles) + "\\PowerShell"; | ||
|
||
if (fs.existsSync(psCoreInstallPath)) { | ||
const arch = platformDetails.isProcess64Bit ? "(x64)" : "(x86)"; | ||
const psCorePaths = | ||
fs.readdirSync(psCoreInstallPath) | ||
.map((item) => path.join(psCoreInstallPath, item)) | ||
.filter((item) => { | ||
const exePath = path.join(item, "pwsh.exe"); | ||
return fs.lstatSync(item).isDirectory() && fs.existsSync(exePath); | ||
}) | ||
.map((item) => ({ | ||
versionName: `PowerShell Core ${path.parse(item).base} ${arch}`, | ||
exePath: path.join(item, "pwsh.exe"), | ||
})); | ||
|
||
if (psCorePaths) { | ||
paths = paths.concat(psCorePaths); | ||
} | ||
} | ||
} else { | ||
// Handle Linux and macOS case | ||
let exePaths: string[]; | ||
|
||
if (platformDetails.operatingSystem === OperatingSystem.Linux) { | ||
exePaths = [ linuxExePath, snapExePath, linuxPreviewExePath, snapPreviewExePath ]; | ||
} else { | ||
exePaths = [ macOSExePath, macOSPreviewExePath ]; | ||
} | ||
|
||
exePaths.forEach((exePath) => { | ||
if (fs.existsSync(exePath)) { | ||
paths.push({ | ||
versionName: "PowerShell Core" + (/-preview/.test(exePath) ? " Preview" : ""), | ||
exePath, | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
// When unit testing, we don't have session settings available to test, so skip reading this setting | ||
if (sessionSettings) { | ||
// Add additional PowerShell paths as configured in settings | ||
for (const additionalPowerShellExePath of sessionSettings.powerShellAdditionalExePaths) { | ||
paths.push({ | ||
versionName: additionalPowerShellExePath.versionName, | ||
exePath: additionalPowerShellExePath.exePath, | ||
}); | ||
} | ||
} | ||
|
||
return paths; | ||
} |
Oops, something went wrong.