Compare commits
1 Commits
main
...
f463970b6b
| Author | SHA1 | Date | |
|---|---|---|---|
| f463970b6b |
@@ -1,10 +1 @@
|
||||
# Newton
|
||||
|
||||
# Additional Tools
|
||||
* [Fzf](https://github.com/junegunn/fzf)
|
||||
* [bat (cat but has highlighting)](https://github.com/sharkdp/bat)
|
||||
* [ripgrep (very fast grep alternative)](https://github.com/BurntSushi/ripgrep/tree/master)
|
||||
|
||||
`
|
||||
sudo pacman -Sy bat ripgrep fzf
|
||||
`
|
||||
@@ -43,11 +43,12 @@
|
||||
"styles":[
|
||||
"node_modules/bootstrap/scss/bootstrap.scss",
|
||||
"node_modules/bootstrap-icons/font/bootstrap-icons.css",
|
||||
"src/assets/css/overrides.css",
|
||||
"src/assets/css/styles.css",
|
||||
"src/assets/css/overrides.css"
|
||||
"src/assets/css/ace-overrides.css"
|
||||
],
|
||||
"scripts":[
|
||||
"src/libs/showdown.min.js"
|
||||
],
|
||||
"optimization": true
|
||||
},
|
||||
|
||||
@@ -5,7 +5,6 @@ const { menu } = require('./menu');
|
||||
const { systemTray } = require('./system-tray');
|
||||
const { argsParser } = require('./args-parser');
|
||||
const { settingsManager } = require('./settings-manager');
|
||||
const { terminal } = require('./terminal');
|
||||
const { newtonFs } = require('./fs');
|
||||
const { newtonIPC } = require('./ipc');
|
||||
|
||||
@@ -54,23 +53,8 @@ const createWindow = (startType = "build", debug = false, args = []) => {
|
||||
window.webContents.send('load-files', args);
|
||||
});
|
||||
|
||||
window.webContents.on('did-finish-load', () => {
|
||||
const cssFiles = [
|
||||
path.join(newtonFs.CONFIG_PATH, 'override.css')
|
||||
];
|
||||
|
||||
const jsFiles = [
|
||||
// path.join(newtonFs.CONFIG_PATH, 'scripts', 'script1.js'),
|
||||
// path.join(newtonFs.CONFIG_PATH, 'scripts', 'script2.js')
|
||||
];
|
||||
|
||||
cssFiles.forEach(cssFile => newtonFs.readAndInjectCSS(window, cssFile));
|
||||
jsFiles.forEach(jsFile => newtonFs.readAndInjectJS(window, jsFile));
|
||||
});
|
||||
|
||||
menu.load(window);
|
||||
systemTray.load(menu.menuStruct);
|
||||
terminal.load(window);
|
||||
|
||||
// window.setAutoHideMenuBar(true)
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
const { app } = require('electron');
|
||||
|
||||
|
||||
let startType = "build";
|
||||
let ipcPort = "4563";
|
||||
let isDebug = false;
|
||||
let args = [];
|
||||
let startType = "build";
|
||||
let isDebug = false;
|
||||
let args = [];
|
||||
|
||||
|
||||
|
||||
@@ -18,13 +17,6 @@ const loadKWArgs = () => {
|
||||
console.log(startType);
|
||||
}
|
||||
|
||||
const hasIpcPort = app.commandLine.hasSwitch("ipc-port");
|
||||
if (hasIpcPort) {
|
||||
ipcPort = app.commandLine.getSwitchValue("ipc-port");
|
||||
console.log("Has ipc-port switch...");
|
||||
console.log(ipcPort);
|
||||
}
|
||||
|
||||
const hasDebug = app.commandLine.hasSwitch("app-debug");
|
||||
if (hasDebug) {
|
||||
isDebug = app.commandLine.getSwitchValue("app-debug");
|
||||
@@ -33,29 +25,38 @@ const loadKWArgs = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const filterOutLaunchAndKWArgs = () => {
|
||||
const loadVArgs = () => {
|
||||
console.log("\n\nStart VArgs:");
|
||||
|
||||
if (
|
||||
process.argv[0].endsWith("electron")
|
||||
) {
|
||||
process.argv = process.argv.slice(2);
|
||||
}
|
||||
|
||||
do {
|
||||
if (
|
||||
process.argv[0].endsWith("/newton") ||
|
||||
process.argv[0].endsWith(".AppImage")
|
||||
) {
|
||||
process.argv = process.argv.slice(1);
|
||||
} while (
|
||||
process.argv.length > 0 &&
|
||||
(
|
||||
process.argv[0].endsWith("/newton") ||
|
||||
process.argv[0].endsWith(".AppImage") ||
|
||||
process.argv[0].includes("--trace-warnings") ||
|
||||
process.argv[0].includes("--start-as") ||
|
||||
process.argv[0].includes("--ipc-port")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( process.argv.length > 0 && (
|
||||
process.argv[0].includes("--trace-warnings") ||
|
||||
process.argv[0].includes("--start-as")
|
||||
)
|
||||
) {
|
||||
process.argv = process.argv.slice(1);
|
||||
}
|
||||
|
||||
if ( process.argv.length > 0 && (
|
||||
process.argv[0].includes("--trace-warnings") ||
|
||||
process.argv[0].includes("--start-as")
|
||||
)
|
||||
) {
|
||||
process.argv = process.argv.slice(1);
|
||||
}
|
||||
|
||||
const loadVArgs = () => {
|
||||
console.log("\n\nStart VArgs:");
|
||||
args = process.argv;
|
||||
args.forEach((val, index, array) => {
|
||||
console.log(index + ': ' + val);
|
||||
@@ -66,7 +67,6 @@ const loadVArgs = () => {
|
||||
|
||||
const loadArgs = () => {
|
||||
loadKWArgs();
|
||||
filterOutLaunchAndKWArgs();
|
||||
loadVArgs();
|
||||
}
|
||||
|
||||
@@ -83,10 +83,6 @@ const getDebugMode = () => {
|
||||
return isDebug;
|
||||
}
|
||||
|
||||
const getIpcPort = () => {
|
||||
return ipcPort;
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
argsParser: {
|
||||
@@ -94,6 +90,5 @@ module.exports = {
|
||||
getArgs: getArgs,
|
||||
getStartType: getStartType,
|
||||
getDebugMode: getDebugMode,
|
||||
getIpcPort: getIpcPort,
|
||||
}
|
||||
};
|
||||
26
newton/fs.js
26
newton/fs.js
@@ -114,6 +114,7 @@ const chooseFolder = () => {
|
||||
console.debug("Canceled folder selection...");
|
||||
return "";
|
||||
}
|
||||
console.log(response)
|
||||
|
||||
return response.filePaths[0];
|
||||
});
|
||||
@@ -185,33 +186,10 @@ const closeFile = (fpath) => {
|
||||
unwatchFile(fpath);
|
||||
}
|
||||
|
||||
const readAndInjectCSS = (window, filePath) => {
|
||||
fs.readFile(filePath, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
console.error(`Error reading CSS file: ${filePath}`, err);
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.insertCSS(data);
|
||||
});
|
||||
}
|
||||
|
||||
const readAndInjectJS = (window, filePath) => {
|
||||
fs.readFile(filePath, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
console.error(`Error reading JS file: ${filePath}`, err);
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.executeJavaScript(data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
newtonFs: {
|
||||
CONFIG_PATH: CONFIG_PATH,
|
||||
setWindow: setWindow,
|
||||
chooseFolder: chooseFolder,
|
||||
openFiles: openFiles,
|
||||
@@ -223,8 +201,6 @@ module.exports = {
|
||||
getLspConfigData: getLspConfigData,
|
||||
getSettingsConfigData: getSettingsConfigData,
|
||||
saveSettingsConfigData: saveSettingsConfigData,
|
||||
readAndInjectJS: readAndInjectJS,
|
||||
readAndInjectCSS: readAndInjectCSS,
|
||||
loadFilesWatcher: loadFilesWatcher,
|
||||
unwatchFile: unwatchFile,
|
||||
}
|
||||
|
||||
@@ -8,17 +8,12 @@ const fetch = require('electron-fetch').default
|
||||
const IPC_SERVER_IP = "127.0.0.1";
|
||||
let window = null;
|
||||
let ipcServer = null;
|
||||
let ipcServerPort = "";
|
||||
let ipcServerURL = "";
|
||||
let ipcServerPort = "4563";
|
||||
let ipcServerURL = `http://${IPC_SERVER_IP}:${ipcServerPort}`;
|
||||
|
||||
|
||||
const setWindow = (win) => {
|
||||
window = win;
|
||||
}
|
||||
|
||||
const configure = (ipcPort) => {
|
||||
ipcServerPort = ipcPort;
|
||||
ipcServerURL = `http://${IPC_SERVER_IP}:${ipcServerPort}`;
|
||||
window = win;
|
||||
}
|
||||
|
||||
const loadIPCServer = (fpath) => {
|
||||
@@ -42,9 +37,6 @@ const loadIPCServer = (fpath) => {
|
||||
console.debug("Load File(s) : ", req.body);
|
||||
|
||||
window.webContents.send('load-files', req.body);
|
||||
window.show();
|
||||
window.focus();
|
||||
|
||||
res.status(200).send('');
|
||||
});
|
||||
|
||||
@@ -55,8 +47,7 @@ const loadIPCServer = (fpath) => {
|
||||
}
|
||||
|
||||
const isIPCServerUp = async () => {
|
||||
const response = await fetch(`${ipcServerURL}/is-up`)
|
||||
.catch((err) => {
|
||||
const response = await fetch(`${ipcServerURL}/is-up`).catch((err) => {
|
||||
console.debug("IPCServer (status) : Not up; okay to start.");
|
||||
return {
|
||||
text: () => {
|
||||
@@ -82,10 +73,9 @@ const sendFilesToIPC = async (files) => {
|
||||
|
||||
module.exports = {
|
||||
newtonIPC: {
|
||||
configure: configure,
|
||||
setWindow: setWindow,
|
||||
loadIPCServer: loadIPCServer,
|
||||
isIPCServerUp: isIPCServerUp,
|
||||
sendFilesToIPC: sendFilesToIPC,
|
||||
setWindow: setWindow
|
||||
}
|
||||
};
|
||||
@@ -80,7 +80,6 @@ app.whenReady().then(async () => {
|
||||
loadProcessSignalHandlers();
|
||||
newton.args.loadArgs();
|
||||
|
||||
newton.ipc.configure( newton.args.getIpcPort() );
|
||||
if ( !await newton.ipc.isIPCServerUp() ) {
|
||||
newton.ipc.loadIPCServer();
|
||||
} else {
|
||||
|
||||
@@ -22,9 +22,6 @@ const load = (win) => {
|
||||
}, {
|
||||
label: 'Terminal',
|
||||
click: () => {}
|
||||
}, {
|
||||
label: "Quit",
|
||||
click: () => win.webContents.send('menu-actions', "quit")
|
||||
}
|
||||
]
|
||||
}, {
|
||||
|
||||
@@ -9,7 +9,6 @@ contextBridge.exposeInMainWorld('electron', {
|
||||
|
||||
contextBridge.exposeInMainWorld('main', {
|
||||
onMenuActions: (callback) => ipcRenderer.on('menu-actions', (_event, action) => callback(action)),
|
||||
onTerminalActions: (callback) => ipcRenderer.on('terminal-actions', (_event, action) => callback(action)),
|
||||
quit: () => ipcRenderer.invoke("quit"),
|
||||
toggleFullScreen: () => ipcRenderer.invoke("toggleFullScreen"),
|
||||
});
|
||||
|
||||
@@ -33,9 +33,6 @@ const load = (win) => {
|
||||
}, {
|
||||
label: 'Help',
|
||||
click: () => win.webContents.send('menu-actions', "show-about")
|
||||
}, {
|
||||
label: 'Quit',
|
||||
click: () => win.webContents.send('menu-actions', "quit")
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
const { ipcMain } = require('electron');
|
||||
// const pty = require('node-pty');
|
||||
const os = require("os");
|
||||
|
||||
|
||||
const shell = "win32" === os.platform() ? "powershell.exe" : "bash";
|
||||
|
||||
|
||||
const load = (win) => {
|
||||
// const ptyProcess = pty.spawn(shell, [], {
|
||||
// name: "xterm-color",
|
||||
// cols: 172,
|
||||
// rows: 256,
|
||||
// cwd: process.env.HOME,
|
||||
// env: process.env
|
||||
// });
|
||||
|
||||
// ptyProcess.on('data', function(data) {
|
||||
// win.webContents.send("terminal-actions", data);
|
||||
// });
|
||||
|
||||
// ipcMain.on("terminal-keystroke", (event, key) => {
|
||||
// ptyProcess.write(key);
|
||||
// });
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
terminal: {
|
||||
load: load
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
65
package.json
65
package.json
@@ -9,18 +9,15 @@
|
||||
"main": "newton/main.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"app": "ng build --base-href ./ && electron . --trace-warnings --start-as=build --ipc-port=4588",
|
||||
"electron-start": "electron . --trace-warnings --start-as=build --ipc-port=4588",
|
||||
"app": "ng build --base-href ./ && electron . --trace-warnings --start-as=build",
|
||||
"electron-start": "electron . --trace-warnings --start-as=build",
|
||||
"electron-pack": "ng build --base-href ./ && electron-builder --dir",
|
||||
"electron-dist": "ng build --base-href ./ && electron-builder",
|
||||
"electron-dist-zip-linux": "ng build --base-href ./ && electron-builder --linux zip",
|
||||
"electron-dist-deb-linux": "ng build --base-href ./ && electron-builder --linux deb",
|
||||
"electron-dist-appimage-linux": "ng build --base-href ./ && electron-builder --linux AppImage",
|
||||
"electron-dist-all-linux": "ng build --base-href ./ && electron-builder --linux deb zip AppImage",
|
||||
"electron-dist-linux": "ng build --base-href ./ && electron-builder --linux deb zip AppImage",
|
||||
"electron-dist-all": "ng build --base-href ./ && electron-builder -mwl",
|
||||
"electron-concurrently": "concurrently 'ng serve' 'electron . --trace-warnings --start-as=ng-serve'",
|
||||
"ng-serve": "ng serve",
|
||||
"ng-build": "ng build --base-href ./",
|
||||
"ng-build": "ng build",
|
||||
"ng-watch-build": "ng build --watch --configuration development",
|
||||
"ng-test": "ng test",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
@@ -30,7 +27,10 @@
|
||||
"icon": "./icos/",
|
||||
"files": [
|
||||
"newton/",
|
||||
"build/"
|
||||
"build/",
|
||||
"!node_modules/ace-builds/",
|
||||
"!node_modules/web-streams-polyfill/",
|
||||
"!node_modules/@angular/"
|
||||
],
|
||||
"mac": {
|
||||
"category": "public.app-category.developer-tools"
|
||||
@@ -44,70 +44,43 @@
|
||||
"maintainer": "ITDominator"
|
||||
}
|
||||
},
|
||||
"overrides": {
|
||||
"glob": "9.0.0",
|
||||
"rimraf": "4.3.1"
|
||||
},
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"dependencies": {
|
||||
"@angular/cdk": "19.2.0",
|
||||
"@angular/common": "19.2.0",
|
||||
"@angular/core": "19.2.0",
|
||||
"@angular/forms": "19.2.0",
|
||||
"@angular/platform-browser": "19.2.0",
|
||||
"ace-builds": "1.43.0",
|
||||
"ace-diff": "3.0.3",
|
||||
"ace-layout": "1.5.0",
|
||||
"ace-linters": "1.8.3",
|
||||
"ace-linters": "1.7.0",
|
||||
"bootstrap": "5.3.6",
|
||||
"bootstrap-icons": "1.12.1",
|
||||
"chokidar": "4.0.3",
|
||||
"electron-fetch": "1.9.1",
|
||||
"express": "4.18.2",
|
||||
"marked": "16.4.0",
|
||||
"node-fetch": "3.3.2",
|
||||
"rxjs": "7.8.0",
|
||||
"socket.io": "4.8.1",
|
||||
"uuid": "11.1.0",
|
||||
"zone.js": "0.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ace-builds": "1.43.0",
|
||||
"@angular-devkit/build-angular": "19.2.8",
|
||||
"@angular/cdk": "19.2.0",
|
||||
"@angular/common": "19.2.0",
|
||||
"@angular/core": "19.2.0",
|
||||
"@angular/cli": "19.2.8",
|
||||
"@angular/compiler-cli": "19.2.0",
|
||||
"@angular/forms": "19.2.0",
|
||||
"@angular/platform-browser": "19.2.0",
|
||||
"@types/express": "4.17.17",
|
||||
"@types/jasmine": "5.1.0",
|
||||
"@types/node": "18.18.0",
|
||||
"concurrently": "9.1.2",
|
||||
"electron": "36.2.0",
|
||||
"@electron/remote": "2.1.2",
|
||||
"electron-builder": "22.7.0",
|
||||
"electron-builder": "26.0.12",
|
||||
"jasmine-core": "5.6.0",
|
||||
"jimp": "1.6.0",
|
||||
"karma": "6.4.0",
|
||||
"karma-chrome-launcher": "3.2.0",
|
||||
"karma-coverage": "2.2.0",
|
||||
"karma-jasmine": "5.1.0",
|
||||
"karma-jasmine-html-reporter": "2.1.0",
|
||||
"nanoevents": "9.1.0",
|
||||
"rxjs": "7.8.0",
|
||||
"tree-sitter": "0.21.1",
|
||||
"tree-sitter-bash": "0.23.2",
|
||||
"tree-sitter-c": "0.23.1",
|
||||
"tree-sitter-cli": "0.25.8",
|
||||
"tree-sitter-cpp": "0.23.4",
|
||||
"tree-sitter-css": "0.23.0",
|
||||
"tree-sitter-go": "0.23.4",
|
||||
"tree-sitter-html": "0.23.2",
|
||||
"tree-sitter-java": "0.23.5",
|
||||
"tree-sitter-javascript": "0.23.1",
|
||||
"tree-sitter-json": "0.24.8",
|
||||
"tree-sitter-lua": "2.1.3",
|
||||
"tree-sitter-php": "0.23.12",
|
||||
"tree-sitter-python": "0.23.2",
|
||||
"tree-sitter-r": "0.0.1-security",
|
||||
"tree-sitter-sql": "0.1.0",
|
||||
"tree-sitter-sqlite": "0.0.1-security",
|
||||
"tree-sitter-toml": "0.5.1",
|
||||
"tree-sitter-typescript": "0.23.2",
|
||||
"tree-sitter-yaml": "0.5.0",
|
||||
"tslib": "2.3.0",
|
||||
"typescript": "5.7.2"
|
||||
}
|
||||
|
||||
@@ -8,78 +8,62 @@
|
||||
"command": "lsp-ws-proxy --listen 4114 -- jdtls",
|
||||
"alt-command": "lsp-ws-proxy -- jdtls",
|
||||
"alt-command2": "java-language-server",
|
||||
"socket": "ws://127.0.0.1:9999/java",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=jdtls",
|
||||
"alt-socket": "ws://127.0.0.1:9999/?name=java-language-server",
|
||||
"socket": "ws://127.0.0.1:4114/?name=jdtls",
|
||||
"alt-socket": "ws://127.0.0.1:3030/?name=java-language-server",
|
||||
"initialization-options": {
|
||||
"bundles": [
|
||||
"intellicode-core.jar"
|
||||
],
|
||||
"workspaceFolders": [
|
||||
"file://{workspace.folder}"
|
||||
"file://"
|
||||
],
|
||||
"extendedClientCapabilities": {
|
||||
"classFileContentsSupport": true,
|
||||
"executeClientCommandSupport": false
|
||||
"executeClientCommandSupport": true
|
||||
},
|
||||
"settings": {
|
||||
"java": {
|
||||
"autobuild": {
|
||||
"enabled": true
|
||||
"enabled": false
|
||||
},
|
||||
"jdt": {
|
||||
"ls": {
|
||||
"javac": {
|
||||
"enabled": true
|
||||
},
|
||||
"java": {
|
||||
"home": "{user.home}/Portable_Apps/sdks/javasdk/jdk-22.0.2"
|
||||
},
|
||||
"lombokSupport": {
|
||||
"enabled": true
|
||||
},
|
||||
"protobufSupport":{
|
||||
"enabled": true
|
||||
},
|
||||
"androidSupport": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
"completion": {
|
||||
"enabled": true,
|
||||
"importOrder": [
|
||||
"java",
|
||||
"javax",
|
||||
"org",
|
||||
"com"
|
||||
]
|
||||
},
|
||||
"configuration": {
|
||||
"updateBuildConfiguration": "automatic",
|
||||
"maven": {
|
||||
"userSettings": "{user.home}/.config/lsps/jdtls/settings.xml",
|
||||
"globalSettings": "{user.home}/.config/lsps/jdtls/settings.xml"
|
||||
"userSettings": "{user.home}/.config/jdtls/settings.xml",
|
||||
"globalSettings": "{user.home}/.config/jdtls/settings.xml"
|
||||
},
|
||||
"runtimes": [
|
||||
{
|
||||
"name": "JavaSE-17",
|
||||
"path": "/usr/lib/jvm/java-17-openjdk",
|
||||
"path": "/usr/lib/jvm/default-runtime",
|
||||
"javadoc": "https://docs.oracle.com/en/java/javase/17/docs/api/",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "JavaSE-22",
|
||||
"path": "{user.home}/Portable_Apps/sdks/javasdk/jdk-22.0.2",
|
||||
"javadoc": "https://docs.oracle.com/en/java/javase/22/docs/api/",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"classPath": [
|
||||
"{user.home}/.config/lsps/jdtls/m2/repository/**/*-sources.jar",
|
||||
"{user.home}/.config/jdtls/m2/repository/**/*-sources.jar",
|
||||
"lib/**/*-sources.jar"
|
||||
],
|
||||
"docPath": [
|
||||
"{user.home}/.config/lsps/jdtls/m2/repository/**/*-javadoc.jar",
|
||||
"{user.home}/.config/jdtls/m2/repository/**/*-javadoc.jar",
|
||||
"lib/**/*-javadoc.jar"
|
||||
],
|
||||
"silentNotification": true,
|
||||
"project": {
|
||||
"encoding": "ignore",
|
||||
"outputPath": "bin",
|
||||
"referencedLibraries": [
|
||||
"{user.home}/.config/lsps/jdtls/m2/repository/**/*.jar",
|
||||
"lib/**/*.jar"
|
||||
"lib/**/*.jar",
|
||||
"{user.home}/.config/jdtls/m2/repository/**/*.jar"
|
||||
],
|
||||
"importOnFirstTimeStartup": "automatic",
|
||||
"importHint": true,
|
||||
@@ -89,7 +73,7 @@
|
||||
],
|
||||
"sourcePaths": [
|
||||
"src",
|
||||
"{user.home}/.config/lsps/jdtls/m2/repository/**/*.jar"
|
||||
"{user.home}/.config/jdtls/m2/repository/**/*.jar"
|
||||
]
|
||||
},
|
||||
"sources": {
|
||||
@@ -119,9 +103,9 @@
|
||||
"enabled": true
|
||||
},
|
||||
"version": "",
|
||||
"home": "{user.home}/Portable_Apps/sdks/gradle/gradle-9.0.0",
|
||||
"home": "abs(static/gradle-7.3.3)",
|
||||
"java": {
|
||||
"home": "{user.home}/Portable_Apps/sdks/javasdk/jdk-22.0.2"
|
||||
"home": "abs(static/launch_jres/17.0.6-linux-x86_64)"
|
||||
},
|
||||
"offline": {
|
||||
"enabled": false
|
||||
@@ -147,65 +131,14 @@
|
||||
"downloadSources": true,
|
||||
"updateSnapshots": true
|
||||
},
|
||||
"silentNotification": true,
|
||||
"contentProvider": {
|
||||
"preferred": "fernflower"
|
||||
},
|
||||
"signatureHelp": {
|
||||
"enabled": true,
|
||||
"description": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"completion": {
|
||||
"enabled": true,
|
||||
"matchCase": "firstletter",
|
||||
"maxResults": 25,
|
||||
"guessMethodArguments": true,
|
||||
"lazyResolveTextEdit": {
|
||||
"enabled": true
|
||||
},
|
||||
"postfix": {
|
||||
"enabled": true
|
||||
},
|
||||
"favoriteStaticMembers": [
|
||||
"org.junit.Assert.*",
|
||||
"org.junit.Assume.*",
|
||||
"org.junit.jupiter.api.Assertions.*",
|
||||
"org.junit.jupiter.api.Assumptions.*",
|
||||
"org.junit.jupiter.api.DynamicContainer.*",
|
||||
"org.junit.jupiter.api.DynamicTest.*"
|
||||
],
|
||||
"importOrder": [
|
||||
"#",
|
||||
"java",
|
||||
"javax",
|
||||
"org",
|
||||
"com"
|
||||
]
|
||||
},
|
||||
"references": {
|
||||
"includeAccessors": true,
|
||||
"includeDecompiledSources": true
|
||||
},
|
||||
"codeGeneration": {
|
||||
"toString": {
|
||||
"template": "${object.className}{${member.name()}=${member.value}, ${otherMembers}}"
|
||||
},
|
||||
"insertionLocation": "afterCursor",
|
||||
"useBlocks": true
|
||||
},
|
||||
"implementationsCodeLens": {
|
||||
"enabled": true
|
||||
},
|
||||
"referencesCodeLens": {
|
||||
"enabled": true
|
||||
},
|
||||
"progressReports": {
|
||||
"enabled": false
|
||||
},
|
||||
"saveActions": {
|
||||
"organizeImports": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,39 +150,53 @@
|
||||
"alt-command": "pylsp",
|
||||
"alt-command2": "lsp-ws-proxy --listen 4114 -- pylsp",
|
||||
"alt-command3": "pylsp --ws --port 4114",
|
||||
"socket": "ws://127.0.0.1:9999/python",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=pylsp",
|
||||
"socket": "ws://127.0.0.1:9999/?name=pylsp",
|
||||
"initialization-options": {
|
||||
"pylsp": {
|
||||
"rope": {
|
||||
"ropeFolder": "{user.home}/.config/lsps/ropeproject"
|
||||
},
|
||||
"pyls": {
|
||||
"plugins": {
|
||||
"ruff": {
|
||||
"enabled": true,
|
||||
"extendSelect": ["I"],
|
||||
"lineLength": 80
|
||||
},
|
||||
"pycodestyle": {
|
||||
"enabled": false
|
||||
},
|
||||
"pydocstyle": {
|
||||
"enabled": false
|
||||
},
|
||||
"pyflakes": {
|
||||
"enabled": false
|
||||
},
|
||||
"pylint": {
|
||||
"enabled": true
|
||||
"enabled": false
|
||||
},
|
||||
"mccabe": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"pylsp": {
|
||||
"plugins": {
|
||||
"pycodestyle": {
|
||||
"enabled": false
|
||||
},
|
||||
"pydocstyle": {
|
||||
"enabled": false
|
||||
},
|
||||
"pyflakes": {
|
||||
"enabled": false
|
||||
},
|
||||
"pylint": {
|
||||
"enabled": false
|
||||
},
|
||||
"mccabe": {
|
||||
"enabled": false
|
||||
},
|
||||
"ruff": true,
|
||||
"pylsp_rope": {
|
||||
"rename": false
|
||||
"rename": true
|
||||
},
|
||||
"rope_rename": {
|
||||
"enabled": false
|
||||
"enabled": true
|
||||
},
|
||||
"rope_autoimport": {
|
||||
"enabled": false
|
||||
"enabled": true
|
||||
},
|
||||
"rope_completion": {
|
||||
"enabled": false,
|
||||
@@ -262,13 +209,13 @@
|
||||
"enabled": true,
|
||||
"include_class_objects": true,
|
||||
"include_function_objects": true,
|
||||
"fuzzy": false
|
||||
"fuzzy": true
|
||||
},
|
||||
"jedi": {
|
||||
"root_dir": "file://{workspace.folder}",
|
||||
"jedi":{
|
||||
"extra_paths": [
|
||||
"{user.home}/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
|
||||
]
|
||||
],
|
||||
"root_dir": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,8 +226,7 @@
|
||||
"info": "https://pypi.org/project/jedi-language-server/",
|
||||
"command": "jedi-language-server",
|
||||
"alt-command": "lsp-ws-proxy --listen 3030 -- jedi-language-server",
|
||||
"socket": "ws://127.0.0.1:9999/python",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=jedi-language-server",
|
||||
"socket": "ws://127.0.0.1:3030/?name=jedi-language-server",
|
||||
"initialization-options": {
|
||||
"jediSettings": {
|
||||
"autoImportModules": [],
|
||||
@@ -299,13 +245,7 @@
|
||||
],
|
||||
"environmentPath": "{user.home}/Portable_Apps/py-venvs/gtk-apps-venv/venv/bin/python",
|
||||
"symbols": {
|
||||
"ignoreFolders": [
|
||||
".nox",
|
||||
".tox",
|
||||
".venv",
|
||||
"__pycache__",
|
||||
"venv"
|
||||
],
|
||||
"ignoreFolders": [".nox", ".tox", ".venv", "__pycache__", "venv"],
|
||||
"maxSymbols": 20
|
||||
}
|
||||
}
|
||||
@@ -315,8 +255,28 @@
|
||||
"info": "https://clangd.llvm.org/",
|
||||
"command": "lsp-ws-proxy -- clangd",
|
||||
"alt-command": "clangd",
|
||||
"socket": "ws://127.0.0.1:9999/cpp",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=clangd",
|
||||
"socket": "ws://127.0.0.1:3030/?name=clangd",
|
||||
"initialization-options": {}
|
||||
},
|
||||
"sh": {
|
||||
"info": "",
|
||||
"command": "",
|
||||
"alt-command": "",
|
||||
"socket": "ws://127.0.0.1:3030/?name=shell",
|
||||
"initialization-options": {}
|
||||
},
|
||||
"go": {
|
||||
"info": "https://pkg.go.dev/golang.org/x/tools/gopls#section-readme",
|
||||
"command": "lsp-ws-proxy -- gopls",
|
||||
"alt-command": "gopls",
|
||||
"socket": "ws://127.0.0.1:3030/?name=gopls",
|
||||
"initialization-options": {}
|
||||
},
|
||||
"lua": {
|
||||
"info": "https://github.com/LuaLS/lua-language-server",
|
||||
"command": "lsp-ws-proxy -- lua-language-server",
|
||||
"alt-command": "lua-language-server",
|
||||
"socket": "ws://127.0.0.1:3030/?name=gopls",
|
||||
"initialization-options": {}
|
||||
},
|
||||
"c": {
|
||||
@@ -324,40 +284,7 @@
|
||||
"info": "https://clangd.llvm.org/",
|
||||
"command": "lsp-ws-proxy -- clangd",
|
||||
"alt-command": "clangd",
|
||||
"socket": "ws://127.0.0.1:9999/c",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=clangd",
|
||||
"initialization-options": {}
|
||||
},
|
||||
"go": {
|
||||
"info": "https://pkg.go.dev/golang.org/x/tools/gopls#section-readme",
|
||||
"command": "lsp-ws-proxy -- gopls",
|
||||
"alt-command": "gopls",
|
||||
"socket": "ws://127.0.0.1:9999/go",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=gopls",
|
||||
"initialization-options": {}
|
||||
},
|
||||
"typescript": {
|
||||
"info": "https://github.com/typescript-language-server/typescript-language-server",
|
||||
"command": "lsp-ws-proxy -- typescript-language-server",
|
||||
"alt-command": "typescript-language-server --stdio",
|
||||
"socket": "ws://127.0.0.1:9999/typescript",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=ts",
|
||||
"initialization-options": {}
|
||||
},
|
||||
"sh": {
|
||||
"info": "",
|
||||
"command": "",
|
||||
"alt-command": "",
|
||||
"socket": "ws://127.0.0.1:9999/bash",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=shell",
|
||||
"initialization-options": {}
|
||||
},
|
||||
"lua": {
|
||||
"info": "https://github.com/LuaLS/lua-language-server",
|
||||
"command": "lsp-ws-proxy -- lua-language-server",
|
||||
"alt-command": "lua-language-server",
|
||||
"socket": "ws://127.0.0.1:9999/lua",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=lua",
|
||||
"socket": "ws://127.0.0.1:3030/?name=clangd",
|
||||
"initialization-options": {}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,7 +1,6 @@
|
||||
<div class="col">
|
||||
<info-bar></info-bar>
|
||||
<tabs></tabs>
|
||||
<hr class="tabs-bar-underline"/>
|
||||
<editors></editors>
|
||||
<search-replace></search-replace>
|
||||
<markdown-preview></markdown-preview>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
|
||||
import { WebsocketService } from './common/services/websocket.service';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { InfoBarComponent } from './editor/info-bar/info-bar.component';
|
||||
import { TabsComponent } from './editor/tabs/tabs.component';
|
||||
@@ -30,69 +28,6 @@ import { LspManagerComponent } from "./editor/lsp-manager/lsp-manager.component"
|
||||
export class AppComponent {
|
||||
title = 'Newton';
|
||||
|
||||
protected ws: WebsocketService = inject(WebsocketService);
|
||||
|
||||
|
||||
constructor() {
|
||||
this.checkIfNotElectronMode();
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
checkIfNotElectronMode() {
|
||||
if (
|
||||
window.electron ||
|
||||
window.main ||
|
||||
window.fs
|
||||
) { return; }
|
||||
|
||||
this.setupWebsocket();
|
||||
this.setupWindowBindings();
|
||||
}
|
||||
|
||||
setupWindowBindings() {
|
||||
window.electron ??= {
|
||||
node: () => { return "" },
|
||||
chrome: () => { return "" },
|
||||
electron: () => { return "" },
|
||||
};
|
||||
|
||||
window.main ??= {
|
||||
onMenuActions: () => {},
|
||||
onTerminalActions: () => {},
|
||||
quit: () => {},
|
||||
toggleFullScreen: () => {},
|
||||
};
|
||||
|
||||
window.fs ??= {
|
||||
getLspConfigData: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve("{}");
|
||||
});
|
||||
},
|
||||
getFileContents: () => {},
|
||||
openFiles: () => {},
|
||||
saveFile: () => {},
|
||||
saveFileAs: () => {},
|
||||
chooseFolder: () => {},
|
||||
closeFile: () => {},
|
||||
getPathForFile: () => {},
|
||||
onLoadFiles: () => {},
|
||||
onUpdateFilePath: () => {},
|
||||
onSavedFile: () => {},
|
||||
onChangedFile: () => {},
|
||||
onDeletedFile: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
setupWebsocket() {
|
||||
// TODO: Set with dynamic address and port
|
||||
this.ws.connect('ws://localhost:7272').subscribe(msg => {
|
||||
console.log(msg);
|
||||
console.log(window.fs);
|
||||
// this.ws.send("{ 'text': 'Hello server!' }");
|
||||
});
|
||||
}
|
||||
constructor() {}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
import {
|
||||
Component,
|
||||
DestroyRef,
|
||||
inject
|
||||
} from "@angular/core";
|
||||
import { Component, inject } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
|
||||
@@ -29,18 +25,17 @@ import 'ace-diff/dist/ace-diff-dark.min.css';
|
||||
}
|
||||
})
|
||||
export class DiffModalComponent {
|
||||
readonly #destroyRef: DestroyRef = inject(DestroyRef);
|
||||
|
||||
diffModal!: bootstrap.Modal;
|
||||
|
||||
|
||||
constructor() {
|
||||
this.loadSubscribers();
|
||||
}
|
||||
|
||||
|
||||
private ngAfterViewInit(): void {
|
||||
this.loadDiffView();
|
||||
this.loadSubscribers();
|
||||
}
|
||||
|
||||
private loadDiffView() {
|
||||
|
||||
@@ -37,11 +37,6 @@ export const Keybindings: Array<{}> = [
|
||||
bindKey: {win: "ctrl-r", mac: "ctrl-r"},
|
||||
readOnly: false
|
||||
}, {
|
||||
|
||||
name: "terminalPopup",
|
||||
bindKey: {win: "ctrl-shift-.", mac: "ctrl-shift-."},
|
||||
readOnly: false
|
||||
}, {
|
||||
name: "newFile",
|
||||
bindKey: {win: "ctrl-t", mac: "ctrl-t"},
|
||||
service: "editorsService",
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export abstract class ButtonMap {
|
||||
static LEFT: number = 0;
|
||||
static MIDDLE: number = 1;
|
||||
static RIGHT: number = 2;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import { NewtonFile } from '../types/file.type';
|
||||
})
|
||||
export class DndDirective {
|
||||
@HostBinding('class.fileover') fileOver!: boolean;
|
||||
@Output() fileDropped: EventEmitter<any> = new EventEmitter();
|
||||
@Output() fileDropped = new EventEmitter<any>();
|
||||
|
||||
@HostListener('dragover', ['$event'])
|
||||
onDragOver(evt: any) {
|
||||
|
||||
@@ -11,11 +11,11 @@ import {
|
||||
selector: '[draggable-item]'
|
||||
})
|
||||
export class DraggableDirective {
|
||||
@Output() dragStart: EventEmitter<PointerEvent> = new EventEmitter();
|
||||
@Output() dragMove: EventEmitter<PointerEvent> = new EventEmitter();
|
||||
@Output() dragEnd: EventEmitter<PointerEvent> = new EventEmitter();
|
||||
@Output() dragStart = new EventEmitter<PointerEvent>();
|
||||
@Output() dragMove = new EventEmitter<PointerEvent>();
|
||||
@Output() dragEnd = new EventEmitter<PointerEvent>();
|
||||
|
||||
private dragging: boolean = false;
|
||||
private dragging = false;
|
||||
selected: any;
|
||||
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
selector: '[pane-handle]'
|
||||
})
|
||||
export class PaneHandleDirective {
|
||||
@Output() dragStart: EventEmitter<PointerEvent> = new EventEmitter();
|
||||
@Output() dragMove: EventEmitter<PointerEvent> = new EventEmitter();
|
||||
@Output() dragEnd: EventEmitter<PointerEvent> = new EventEmitter();
|
||||
@Output() dragStart = new EventEmitter<PointerEvent>();
|
||||
@Output() dragMove = new EventEmitter<PointerEvent>();
|
||||
@Output() dragEnd = new EventEmitter<PointerEvent>();
|
||||
|
||||
private dragging: boolean = false;
|
||||
private isHrPane: boolean = false;
|
||||
@@ -31,7 +31,7 @@ export class PaneHandleDirective {
|
||||
!target.classList.contains("hr-pane-handle") &&
|
||||
!target.classList.contains("vr-pane-handle")
|
||||
) {
|
||||
console.error("Must have 'hr-pane-handle' or 'vr-pane-handle' in classList!");
|
||||
console.log("Must have 'hr-pane-handle' or 'vr-pane-handle' in classList!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import * as ace from "ace-builds/src-min-noconflict/ace";
|
||||
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ColorTokenizerService {
|
||||
readonly #RULES: {} = {
|
||||
start: [
|
||||
{ token: "hex3", regex: "#[A-Fa-f0-9]{3}(?![A-Fa-f0-9])" },
|
||||
{ token: "hex6", regex: "#[A-Fa-f0-9]{6}(?![A-Fa-f0-9])" },
|
||||
{ token: "hex8", regex: "#[A-Fa-f0-9]{8}(?![A-Fa-f0-9])" },
|
||||
{
|
||||
token: "rgb",
|
||||
regex: /rgb\s*\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)/
|
||||
},
|
||||
{
|
||||
token: "rgba",
|
||||
regex: /rgba\s*\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*(?:0(?:\.\d+)?|1(?:\.0+)?)\s*\)/
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
tokenizer!: any;
|
||||
cssLines: {} = {};
|
||||
|
||||
|
||||
constructor() {
|
||||
Object.freeze(this.#RULES)
|
||||
|
||||
const Tokenizer = ace.require("ace/tokenizer").Tokenizer;
|
||||
this.tokenizer = new Tokenizer(this.#RULES);
|
||||
}
|
||||
|
||||
|
||||
public async parse(data: string) {
|
||||
const lines = data.split("\n");
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const token = this.parseLine( lines[i] );
|
||||
if (!token) continue;
|
||||
this.cssLines[i] = token;
|
||||
this.cssLines[i]["hash"] = btoa(
|
||||
token["value"]
|
||||
);
|
||||
}
|
||||
|
||||
// console.log(this.cssLines);
|
||||
}
|
||||
|
||||
public parseLine(line: string): {} | null {
|
||||
const tokens = this.tokenizer.getLineTokens(line, "start").tokens;
|
||||
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
if ("text" === tokens[i]["type"]) continue;
|
||||
return tokens[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,15 +15,21 @@ import { EditorType } from '../../types/editor.type';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EditorsService {
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject(1);
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject<ServiceMessage>(1);
|
||||
|
||||
editors: Map<string, CodeViewComponent> = new Map();
|
||||
editorSettings: typeof EditorSettings = EditorSettings;
|
||||
editors: Map<string, CodeViewComponent>;
|
||||
editorSettings: typeof EditorSettings;
|
||||
|
||||
activeEditor: string = "";
|
||||
activeEditor!: string;
|
||||
miniMapView!: CodeViewComponent;
|
||||
|
||||
|
||||
constructor() {
|
||||
this.editorSettings = EditorSettings;
|
||||
this.editors = new Map<string, CodeViewComponent>();
|
||||
}
|
||||
|
||||
|
||||
public getEditorsAsArray(): CodeViewComponent[] {
|
||||
return [...this.editors.values()];
|
||||
}
|
||||
|
||||
@@ -8,11 +8,14 @@ import { ServiceMessage } from '../../../types/service-message.type';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class InfoBarService {
|
||||
private dataSubject: ReplaySubject<ServiceMessage> = new ReplaySubject(1);
|
||||
private fpathSubject: ReplaySubject<string> = new ReplaySubject(1);
|
||||
private cursorPosSubject: ReplaySubject<any> = new ReplaySubject(1);
|
||||
private encodeingSubject: ReplaySubject<string> = new ReplaySubject(1);
|
||||
private ftypeSubject: ReplaySubject<string> = new ReplaySubject(1);
|
||||
private dataSubject: ReplaySubject<ServiceMessage> = new ReplaySubject<ServiceMessage>(1);
|
||||
private fpathSubject: ReplaySubject<string> = new ReplaySubject<string>(1);
|
||||
private cursorPosSubject: ReplaySubject<any> = new ReplaySubject<any>(1);
|
||||
private encodeingSubject: ReplaySubject<string> = new ReplaySubject<string>(1);
|
||||
private ftypeSubject: ReplaySubject<string> = new ReplaySubject<string>(1);
|
||||
|
||||
|
||||
constructor() {}
|
||||
|
||||
|
||||
public setData(data: ServiceMessage): void {
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ReplaySubject, Observable } from 'rxjs';
|
||||
|
||||
import { CompletionProvider } from "ace-builds/src-min-noconflict/ace";
|
||||
import { CommandBarTooltip } from "ace-builds/src-min-noconflict/ext-command_bar";
|
||||
import { InlineAutocomplete } from "ace-builds/src-min-noconflict/ext-inline_autocomplete";
|
||||
|
||||
import { AceLanguageClient, LanguageClientConfig } from 'ace-linters/build/ace-language-client';
|
||||
import { LanguageProvider } from "ace-linters";
|
||||
|
||||
|
||||
|
||||
import { ServiceMessage } from '../../../types/service-message.type';
|
||||
|
||||
|
||||
@@ -18,155 +12,85 @@ import { ServiceMessage } from '../../../types/service-message.type';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class LspManagerService {
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject(1);
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject<ServiceMessage>(1);
|
||||
|
||||
workspaceFolder: string = "";
|
||||
lspConfigDataStr: string = "";
|
||||
languageProviders: {} = {};
|
||||
lspConfigData!: {};
|
||||
languageProviders: {} = {};
|
||||
workspaceFolder: string = "";
|
||||
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
public loadLspConfigData(): Promise<string | void> {
|
||||
return this.getLspConfigData().then((lspConfigData: string) => {
|
||||
this.lspConfigDataStr = lspConfigData;
|
||||
this.lspConfigData = JSON.parse(lspConfigData);
|
||||
|
||||
if (this.lspConfigData["message"]) {
|
||||
console.log(
|
||||
"Warning: LSP this.lspConfigData is a 'message'",
|
||||
this.lspConfigData
|
||||
);
|
||||
|
||||
this.lspConfigData = {};
|
||||
}
|
||||
|
||||
return lspConfigData;
|
||||
});
|
||||
}
|
||||
|
||||
public registerEditorToLSPClient(editor: any) {
|
||||
let mode = this.getMode(editor.session);
|
||||
public registerEditor(editor: any): void {
|
||||
let modeParts = editor.session.getMode()["$Id"].split("/");
|
||||
let mode = modeParts[ modeParts.length - 1 ];
|
||||
|
||||
this.languageProviders[mode]?.registerEditor(
|
||||
editor,
|
||||
editor.session.lspConfig
|
||||
);
|
||||
if ( !this.languageProviders[mode] ) {
|
||||
this.languageProviders[mode] = this.getLanguageProviderWithClientServer(mode);
|
||||
}
|
||||
|
||||
this.languageProviders[mode].registerEditor(editor);
|
||||
}
|
||||
|
||||
private getLspConfigData(): Promise<string> {
|
||||
return window?.fs.getLspConfigData();
|
||||
return window.fs.getLspConfigData();
|
||||
}
|
||||
|
||||
private parseAndReturnLSPConfigData(): {} {
|
||||
let configData = JSON.parse(
|
||||
this.lspConfigDataStr.replaceAll("{workspace.folder}", this.workspaceFolder)
|
||||
);
|
||||
private getLanguageProviderWithClientServer(mode: string) {
|
||||
let _initializationOptions = {};
|
||||
|
||||
if (configData["message"]) {
|
||||
console.warn(
|
||||
"Warning: LSP this.lspConfigDataStr is a 'message'",
|
||||
this.lspConfigDataStr
|
||||
);
|
||||
|
||||
configData = {};
|
||||
if ( Object.keys(this.lspConfigData).length !== 0 && this.lspConfigData[mode] ) {
|
||||
_initializationOptions = this.lspConfigData[mode]["initialization-options"];
|
||||
}
|
||||
|
||||
return configData;
|
||||
}
|
||||
|
||||
private getInitializationOptions(mode: string, configData: {}): {} {
|
||||
let initializationOptions = {};
|
||||
|
||||
if ( Object.keys(configData).length !== 0 && configData[mode] ) {
|
||||
initializationOptions = configData[mode]["initialization-options"];
|
||||
}
|
||||
|
||||
return initializationOptions;
|
||||
}
|
||||
|
||||
public createLanguageProviderWithClientServer(mode: string): LanguageProvider {
|
||||
if ( this.languageProviders[mode] ) return;
|
||||
let servers: LanguageClientConfig[] = [];
|
||||
|
||||
try {
|
||||
let lspConfigData = this.parseAndReturnLSPConfigData();
|
||||
let initializationOptions = this.getInitializationOptions(mode, lspConfigData);
|
||||
servers = [
|
||||
{
|
||||
module: () => import("ace-linters/build/language-client"),
|
||||
modes: mode,
|
||||
type: "socket",
|
||||
socket: new WebSocket( lspConfigData[mode]["socket"] ),
|
||||
initializationOptions: initializationOptions
|
||||
}
|
||||
];
|
||||
} catch(error) {
|
||||
console.error(
|
||||
"Error: Language Server could not be loaded OR doesn't exist in Newton-LSP config setup...",
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.languageProviders[mode] = AceLanguageClient.for(
|
||||
servers,
|
||||
let servers: LanguageClientConfig[] = [
|
||||
{
|
||||
workspacePath: this.workspaceFolder,
|
||||
functionality: {
|
||||
hover: true,
|
||||
completion: {
|
||||
overwriteCompleters: true,
|
||||
lspCompleterOptions: {
|
||||
triggerCharacters: {
|
||||
add: [
|
||||
" ",
|
||||
".",
|
||||
"@"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
// inlineCompletion: {
|
||||
// overwriteCompleters: true
|
||||
// },
|
||||
completionResolve: true,
|
||||
format: true,
|
||||
documentHighlights: true,
|
||||
signatureHelp: true,
|
||||
semanticTokens: true,
|
||||
codeActions: true
|
||||
},
|
||||
// aceComponents: {
|
||||
// InlineAutocomplete,
|
||||
// CommandBarTooltip,
|
||||
// CompletionProvider
|
||||
// },
|
||||
manualSessionControl: true
|
||||
module: () => import("ace-linters/build/language-client"),
|
||||
modes: mode,
|
||||
type: "socket",
|
||||
socket: new WebSocket(`ws://127.0.0.1:9999/${mode}`),
|
||||
// socket: new WebSocket("ws://127.0.0.1:9999/?name=pylsp"),
|
||||
initializationOptions: _initializationOptions
|
||||
}
|
||||
);
|
||||
];
|
||||
|
||||
return this.languageProviders[mode];
|
||||
return AceLanguageClient.for(servers);
|
||||
}
|
||||
|
||||
public closeLanguageProviderWithClientServer(mode: string): LanguageProvider {
|
||||
if ( !this.languageProviders[mode] ) return;
|
||||
|
||||
let connection = this.languageProviders[mode];
|
||||
delete this.languageProviders[mode];
|
||||
connection.closeConnection();
|
||||
}
|
||||
|
||||
private getLanguageProviderWithWebWorker(): LanguageProvider {
|
||||
private getLanguageProviderWithWebWorker() {
|
||||
let worker = new Worker(new URL('./webworker.js', import.meta.url));
|
||||
return LanguageProvider.create(worker);
|
||||
}
|
||||
|
||||
public registerSession(editor: any) {
|
||||
let mode = this.getMode(editor.session);
|
||||
protected setSessionFilePath(session: any, filePath: string = "") {
|
||||
if ( !session || !filePath ) return;
|
||||
let mode = session.getMode()["$Id"];
|
||||
if ( !this.languageProviders[mode] ) return;
|
||||
|
||||
this.languageProviders[mode].registerSession(
|
||||
editor.session,
|
||||
editor,
|
||||
editor.session.lspConfig
|
||||
);
|
||||
this.languageProviders[mode].setSessionFilePath(session, filePath);
|
||||
}
|
||||
|
||||
public getMode(session: any): string {
|
||||
return session.getMode()["$id"].replace("ace/mode/", "");
|
||||
}
|
||||
|
||||
public closeDocument(session: any) {
|
||||
protected closeDocument(session: any) {
|
||||
if ( !session ) return;
|
||||
let mode = this.getMode(session);
|
||||
let mode = session.getMode()["$Id"];
|
||||
if ( !this.languageProviders[mode] ) return;
|
||||
this.languageProviders[mode].closeDocument(session);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,11 @@ import { ServiceMessage } from '../../../types/service-message.type';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MarkdownPreviewService {
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject(1);
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject<ServiceMessage>(1);
|
||||
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
public sendMessage(data: ServiceMessage): void {
|
||||
|
||||
@@ -8,7 +8,11 @@ import { ReplaySubject, Observable } from 'rxjs';
|
||||
})
|
||||
export class FilesModalService {
|
||||
private showFilesModalSubject: ReplaySubject<null> = new ReplaySubject<null>(1);
|
||||
private addFileSubject: ReplaySubject<string> = new ReplaySubject<string>(1);
|
||||
private addFileSubject: ReplaySubject<string> = new ReplaySubject<string>(1);
|
||||
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
public showFilesModal(): void {
|
||||
|
||||
@@ -12,6 +12,10 @@ export class SearchReplaceService {
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject<ServiceMessage>(1);
|
||||
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
public sendMessage(data: ServiceMessage): void {
|
||||
this.messageSubject.next(data);
|
||||
}
|
||||
|
||||
@@ -11,13 +11,15 @@ import { ServiceMessage } from '../../../types/service-message.type';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TabsService {
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject(1);
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject<ServiceMessage>(1);
|
||||
|
||||
private editorsService: EditorsService = inject(EditorsService);
|
||||
|
||||
tabs: any[] = [];
|
||||
newIndex: number = -1;
|
||||
|
||||
constructor() {}
|
||||
|
||||
|
||||
public push(tabData: {}): void {
|
||||
this.tabs.push(tabData);
|
||||
@@ -43,21 +45,45 @@ export class TabsService {
|
||||
}
|
||||
|
||||
public getLeftSiblingTab(fpath: string): string {
|
||||
if (this.tabs.length === 0 ) return;
|
||||
let size = this.tabs.length;
|
||||
let i = 0;
|
||||
|
||||
let i = this.tabs.indexOf(fpath);
|
||||
for (; i < size; i++) {
|
||||
if (this.tabs[i].path == fpath) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(i === 0) ? i = this.tabs.length - 1 : i -= 1;
|
||||
return this.tabs[i].path;
|
||||
if ( !(size > 1) ) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if ( i === 0 ) {
|
||||
return this.tabs[i + 1].path;
|
||||
}
|
||||
|
||||
return this.tabs[i - 1].path;
|
||||
}
|
||||
|
||||
public getRightSiblingTab(fpath: string): string {
|
||||
if (this.tabs.length === 0 ) return;
|
||||
let size = this.tabs.length;
|
||||
let i = 0;
|
||||
|
||||
let i = this.tabs.indexOf(fpath);
|
||||
for (; i < size; i++) {
|
||||
if (this.tabs[i].path == fpath) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(i === (this.tabs.length - 1)) ? i = 0 : i += 1;
|
||||
return this.tabs[i].path;
|
||||
if ( !(size > 1) ) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if ( i === (size - 1) ) {
|
||||
return this.tabs[i - 1].path;
|
||||
}
|
||||
|
||||
return this.tabs[i + 1].path;
|
||||
}
|
||||
|
||||
public setNewTargetIndex(fpath: string): void {
|
||||
|
||||
@@ -5,7 +5,6 @@ import { EditSession, UndoManager } from 'ace-builds';
|
||||
import { getModeForPath } from 'ace-builds/src-noconflict/ext-modelist';
|
||||
|
||||
import { TabsService } from './editor/tabs/tabs.service';
|
||||
import { ColorTokenizerService } from './color-tokenizer.service';
|
||||
|
||||
import { NewtonFile } from '../types/file.type';
|
||||
import { ServiceMessage } from '../types/service-message.type';
|
||||
@@ -16,11 +15,16 @@ import { ServiceMessage } from '../types/service-message.type';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class FilesService {
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject(1);
|
||||
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject<ServiceMessage>(1);
|
||||
|
||||
private tabsService: TabsService = inject(TabsService);
|
||||
|
||||
files: Map<string, NewtonFile> = new Map();
|
||||
files: Map<string, NewtonFile>;
|
||||
|
||||
|
||||
constructor() {
|
||||
this.files = new Map<string, NewtonFile>();
|
||||
}
|
||||
|
||||
|
||||
public get(path: string): NewtonFile {
|
||||
@@ -35,27 +39,9 @@ export class FilesService {
|
||||
return [...this.files.values()];
|
||||
}
|
||||
|
||||
public getPreviousFile(path: string): NewtonFile {
|
||||
let paths = this.getAllPaths();
|
||||
if (paths.length === 0 ) return;
|
||||
|
||||
let i = paths.indexOf(path);
|
||||
(i === 0) ? i = paths.length - 1 : i -= 1;
|
||||
return this.files.get( paths[i] );
|
||||
}
|
||||
|
||||
public getNextFile(path: string): NewtonFile {
|
||||
let paths = this.getAllPaths();
|
||||
if (paths.length === 0 ) return;
|
||||
|
||||
let i = paths.indexOf(path);
|
||||
(i === (paths.length - 1)) ? i = 0 : i += 1;
|
||||
return this.files.get( paths[i] );
|
||||
}
|
||||
|
||||
public unset(file: NewtonFile) {
|
||||
public delete(file: NewtonFile) {
|
||||
file.session.destroy();
|
||||
window?.fs.closeFile(file.path);
|
||||
window.fs.closeFile(file.path);
|
||||
this.files.delete(file.path);
|
||||
}
|
||||
|
||||
@@ -76,7 +62,7 @@ export class FilesService {
|
||||
): Promise<NewtonFile | undefined | null> {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
const path = window?.fs.getPathForFile(file);
|
||||
const path = window.fs.getPathForFile(file);
|
||||
|
||||
if (!file || !path) continue;
|
||||
if ( this.files.get(path) ) continue;
|
||||
@@ -101,22 +87,15 @@ export class FilesService {
|
||||
file.hash = btoa(file.path);
|
||||
|
||||
if (loadFileContents)
|
||||
data = await window?.fs.getFileContents(file.path);
|
||||
data = await window.fs.getFileContents(file.path);
|
||||
|
||||
file.session = new EditSession(data);
|
||||
file.session["id"] = path;
|
||||
file.session = new EditSession(data);
|
||||
file.session.setUndoManager( new UndoManager() );
|
||||
file.session.setMode( getModeForPath( file.path ).mode );
|
||||
file.session["lspConfig"] = {
|
||||
filePath: path,
|
||||
joinWorkspaceURI: false
|
||||
}
|
||||
file.session["colorTokenizer"] = new ColorTokenizerService();
|
||||
file.session["colorTokenizer"].parse(data);
|
||||
|
||||
this.files.set(file.path, file);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
console.log(
|
||||
`---- Error ----\nPath: ${path}\nMessage: ${error}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class WebsocketService {
|
||||
|
||||
private socket$!: WebSocketSubject<any>;
|
||||
|
||||
connect(url: string): Observable<any> {
|
||||
if (!this.socket$ || this.socket$.closed) {
|
||||
this.socket$ = webSocket(
|
||||
{
|
||||
url,
|
||||
deserializer: msg => msg.data
|
||||
}
|
||||
);
|
||||
}
|
||||
return this.socket$.asObservable();
|
||||
}
|
||||
|
||||
send(message: any) {
|
||||
if (this.socket$) {
|
||||
this.socket$.next(message);
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.socket$) {
|
||||
this.socket$.complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
Input,
|
||||
ViewChild,
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import { Directive, ElementRef, Input, ViewChild, inject } from '@angular/core';
|
||||
import * as uuid from 'uuid';
|
||||
|
||||
import { InfoBarService } from '../../common/services/editor/info-bar/info-bar.service';
|
||||
@@ -52,8 +46,9 @@ export class CodeViewBase {
|
||||
public debounceId: number = -1;
|
||||
public debounceWait: number = 800;
|
||||
|
||||
@ViewChild('contextMenu') contextMenu!: ElementRef;
|
||||
public showContextMenu: boolean = false;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
public selectLeftEditor() {
|
||||
@@ -187,7 +182,7 @@ export class CodeViewBase {
|
||||
}
|
||||
|
||||
public toggleFullScreen() {
|
||||
window?.main.toggleFullScreen();
|
||||
window.main.toggleFullScreen();
|
||||
}
|
||||
|
||||
public setAsReadOnly() {
|
||||
@@ -205,8 +200,8 @@ export class CodeViewBase {
|
||||
this.editor.setHighlightGutterLine(false);
|
||||
this.editor.setShowFoldWidgets(false);
|
||||
this.editor.setShowPrintMargin(false);
|
||||
this.editor.session.setUseWrapMode(true);
|
||||
|
||||
this.editorElm.nativeElement.parentElement.classList.remove("scroller");
|
||||
this.editorElm.nativeElement.parentElement.classList.add("col-1");
|
||||
this.editorElm.nativeElement.parentElement.classList.add("zero-margin-padding");
|
||||
|
||||
@@ -300,30 +295,27 @@ export class CodeViewBase {
|
||||
startDir = pathParts.join( '/' );
|
||||
}
|
||||
|
||||
window?.fs.openFiles(startDir);
|
||||
window.fs.openFiles(startDir);
|
||||
}
|
||||
|
||||
protected saveFile() {
|
||||
if (!this.activeFile) {
|
||||
this.saveFileAs();
|
||||
this.activeFile.session.getUndoManager().markClean();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const text = this.activeFile.session.getValue();
|
||||
window?.fs.saveFile(this.activeFile.path, text);
|
||||
this.activeFile.session.getUndoManager().markClean();
|
||||
window.fs.saveFile(this.activeFile.path, text);
|
||||
}
|
||||
|
||||
protected saveFileAs() {
|
||||
window?.fs.saveFileAs().then((path: string) => {
|
||||
window.fs.saveFileAs().then((path: string) => {
|
||||
if (!path) return;
|
||||
|
||||
let file: NewtonFile = new File([""], path, {});
|
||||
const text = this.editor.session.getValue();
|
||||
|
||||
window?.fs.saveFile(path, text);
|
||||
window.fs.saveFile(path, text);
|
||||
this.filesService.addFile(
|
||||
path,
|
||||
file,
|
||||
@@ -364,6 +356,6 @@ export class CodeViewBase {
|
||||
}
|
||||
|
||||
private quit() {
|
||||
window?.main.quit();
|
||||
window.main.quit();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
.editor {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.editor {
|
||||
height: 100vh;
|
||||
width: auto;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
.editor {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
@@ -1,15 +1,2 @@
|
||||
<div class="editor" #editor >
|
||||
</div>
|
||||
|
||||
<ul #contextMenu
|
||||
class="contextMenu"
|
||||
[hidden]="!showContextMenu"
|
||||
(blur)="hideContextMenu()"
|
||||
(click)="contextMenuClicked($event)"
|
||||
>
|
||||
<li command="cutText">Cut</li>
|
||||
<li command="copyText">Copy</li>
|
||||
<li command="pasteText">Paste</li>
|
||||
<hr/>
|
||||
<li command="prettyJSON">Prettify JSON</li>
|
||||
</ul>
|
||||
@@ -2,10 +2,6 @@ import { Component } from "@angular/core";
|
||||
|
||||
// Import Ace and its modes/themes so that `ace` global is defined
|
||||
import * as ace from "ace-builds/src-min-noconflict/ace";
|
||||
|
||||
// Note: https://github.com/mkslanc/ace-linters/blob/c286d85c558530aa1b0597d02108bc782abd4736/packages/demo/file-api-websockets/client.ts#L27
|
||||
// import { AceLayout, Box, TabManager, Button, dom, AceTreeWrapper, FileSystemWeb, Pane, AceEditor, Tab } from "ace-layout";
|
||||
|
||||
import "ace-builds/src-min-noconflict/ext-settings_menu";
|
||||
import "ace-builds/src-min-noconflict/ext-keybinding_menu";
|
||||
import "ace-builds/src-min-noconflict/ext-command_bar";
|
||||
@@ -17,15 +13,11 @@ import "ace-builds/src-min-noconflict/ext-language_tools";
|
||||
// import "ace-builds/src-min-noconflict/theme-penguins_in_space";
|
||||
import "ace-builds/src-min-noconflict/theme-gruvbox";
|
||||
|
||||
// https://www.npmjs.com/package/web-tree-sitter
|
||||
// import { Language, Parser } from 'web-tree-sitter';
|
||||
|
||||
import { CodeViewBase } from './view.base';
|
||||
|
||||
import { NewtonFile } from '../../common/types/file.type';
|
||||
import { EditorType } from '../../common/types/editor.type';
|
||||
import { ServiceMessage } from '../../common/types/service-message.type';
|
||||
import { ButtonMap } from '../../common/constants/button.map';
|
||||
|
||||
|
||||
|
||||
@@ -46,20 +38,6 @@ export class CodeViewComponent extends CodeViewBase {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// const { Parser } = window.TreeSitter;
|
||||
// const { Parser } = TreeSitter;
|
||||
// console.log(treeSitter);
|
||||
|
||||
// treeSitter.Parser.init().then(() => {
|
||||
// console.log("Parser ready...");
|
||||
// });
|
||||
|
||||
// const parser = new Parser();
|
||||
// const JavaScript = await Language.load('/path/to/tree-sitter-javascript.wasm');
|
||||
// Language.load('resources/wasm/tree-sitter-javascript.wasm').then((language) => {
|
||||
// console.log(language);
|
||||
// });
|
||||
|
||||
this.aceApi = ace;
|
||||
}
|
||||
|
||||
@@ -142,7 +120,7 @@ export class CodeViewComponent extends CodeViewBase {
|
||||
private loadNewtonEventBindings(): void {
|
||||
|
||||
// Note: https://ajaxorg.github.io/ace-api-docs/interfaces/ace.Ace.EditorEvents.html
|
||||
this.editor.on("focus", (event) => {
|
||||
this.editor.on("focus", (e) => {
|
||||
let message = new ServiceMessage();
|
||||
message.action = "set-active-editor";
|
||||
message.editorUUID = this.uuid;
|
||||
@@ -150,45 +128,20 @@ export class CodeViewComponent extends CodeViewBase {
|
||||
|
||||
this.editorsService.sendMessage(message);
|
||||
this.searchReplaceService.sendMessage(message);
|
||||
this.lspManagerService.sendMessage(message);
|
||||
|
||||
message = new ServiceMessage();
|
||||
message.action = "set-active-editor";
|
||||
message.rawData = this;
|
||||
this.lspManagerService.sendMessage(message);
|
||||
this.markdownPreviewService.sendMessage(message);
|
||||
|
||||
message = new ServiceMessage();
|
||||
message.action = "highlight-active-tab";
|
||||
message.filePath = this.activeFile?.path;
|
||||
this.tabsService.sendMessage(message);
|
||||
|
||||
this.updateInfoBar();
|
||||
});
|
||||
|
||||
this.editor.on("click", (event) => {
|
||||
this.editor.on("click", () => {
|
||||
this.updateInfoBar();
|
||||
});
|
||||
|
||||
this.editor.addEventListener("mousedown", (event) => {
|
||||
if (ButtonMap.LEFT === event.domEvent.button) {
|
||||
this.showContextMenu = false;
|
||||
} else if (ButtonMap.RIGHT === event.domEvent.button) {
|
||||
let menuElm = this.contextMenu.nativeElement;
|
||||
let pageX = event.domEvent.pageX;
|
||||
let pageY = event.domEvent.pageY;
|
||||
|
||||
const origin = {
|
||||
left: pageX + 5,
|
||||
top: pageY - 5
|
||||
};
|
||||
|
||||
menuElm.style.left = `${origin.left}px`;
|
||||
menuElm.style.top = `${origin.top}px`;
|
||||
this.showContextMenu = true;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
this.editor.on("input", () => {
|
||||
this.updateInfoBar();
|
||||
});
|
||||
@@ -208,71 +161,31 @@ export class CodeViewComponent extends CodeViewBase {
|
||||
}
|
||||
});
|
||||
|
||||
this.editor.on("mousewheel", (event) => {
|
||||
if (event.domEvent.ctrlKey && event.domEvent.deltaY < 0) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.zoomIn();
|
||||
} else if (event.domEvent.ctrlKey && event.domEvent.deltaY > 0) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.zoomOut();
|
||||
}
|
||||
});
|
||||
|
||||
this.editor.on("change", () => {
|
||||
if (this.debounceId) { clearTimeout(this.debounceId); }
|
||||
this.setDebounceTimeout();
|
||||
|
||||
if (!this.activeFile) return;
|
||||
|
||||
const isClean = this.activeFile.session.getUndoManager().isClean();
|
||||
const hasUndo = this.activeFile.session.getUndoManager().hasUndo();
|
||||
let message = new ServiceMessage();
|
||||
message.action = (!isClean && hasUndo) ? "file-changed" : "file-unmodified";
|
||||
message.action = "file-changed";
|
||||
message.filePath = this.activeFile.path;
|
||||
this.tabsService.sendMessage(message);
|
||||
|
||||
});
|
||||
|
||||
this.editor.on("changeSession", (session) => {
|
||||
let message = new ServiceMessage();
|
||||
message.action = "editor-update";
|
||||
message.rawData = this;
|
||||
message.action = "set-active-editor";
|
||||
message.rawData = this.editor;
|
||||
|
||||
this.lspManagerService.sendMessage(message);
|
||||
|
||||
message = new ServiceMessage();
|
||||
message.action = "highlight-active-tab";
|
||||
message.filePath = this.activeFile?.path;
|
||||
this.tabsService.sendMessage(message);
|
||||
|
||||
this.updateInfoBar();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public prettyJSON() {
|
||||
let data = JSON.parse(this.editor.session.getValue());
|
||||
this.editor.session.setValue(
|
||||
JSON.stringify(data, null, 4)
|
||||
);
|
||||
}
|
||||
|
||||
public hideContextMenu() {
|
||||
this.showContextMenu = false;
|
||||
}
|
||||
|
||||
public contextMenuClicked(event: any) {
|
||||
this.showContextMenu = false;
|
||||
|
||||
const command = event.target.getAttribute("command");
|
||||
const args = event.target.getAttribute("args");
|
||||
|
||||
if (!command) return;
|
||||
|
||||
this[command]( (args) ? args : null );
|
||||
}
|
||||
|
||||
public assignSession(file: NewtonFile) {
|
||||
if (!file) return;
|
||||
|
||||
@@ -283,17 +196,10 @@ export class CodeViewComponent extends CodeViewBase {
|
||||
public cloneSession(file: NewtonFile) {
|
||||
if (!file) return;
|
||||
|
||||
this.activeFile = file;
|
||||
let session = this.aceApi.createEditSession(file.session.getValue());
|
||||
session["$config"] = {
|
||||
"lsp": {
|
||||
"filePath": file.path
|
||||
}
|
||||
}
|
||||
this.activeFile = file;
|
||||
let session = this.aceApi.createEditSession(file.session.getValue());
|
||||
|
||||
session.setMode( file.session.getMode()["$id"] );
|
||||
session.setUseWrapMode(true);
|
||||
|
||||
this.editor.setSession(session);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
<code-view [mode]="'mini-map'"></code-view>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, DestroyRef, inject } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
import { EditorsService } from '../common/services/editor/editors.service';
|
||||
import { TabsService } from '../common/services/editor/tabs/tabs.service';
|
||||
@@ -29,7 +29,7 @@ import { ServiceMessage } from '../common/types/service-message.type';
|
||||
}
|
||||
})
|
||||
export class EditorsComponent {
|
||||
readonly #destroyRef: DestroyRef = inject(DestroyRef);
|
||||
private unsubscribe: Subject<void> = new Subject();
|
||||
|
||||
private editorsService: EditorsService = inject(EditorsService);
|
||||
private tabsService: TabsService = inject(TabsService);
|
||||
@@ -37,46 +37,167 @@ export class EditorsComponent {
|
||||
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
private ngAfterViewInit(): void {
|
||||
this.loadSubscribers();
|
||||
this.loadMainSubscribers();
|
||||
}
|
||||
|
||||
private ngOnDestroy() {
|
||||
this.unsubscribe.next();
|
||||
this.unsubscribe.complete();
|
||||
}
|
||||
|
||||
private loadSubscribers() {
|
||||
|
||||
this.editorsService.getMessage$().pipe(
|
||||
takeUntilDestroyed(this.#destroyRef)
|
||||
takeUntil(this.unsubscribe)
|
||||
).subscribe((message: ServiceMessage) => {
|
||||
switch ( message.action ) {
|
||||
case "select-left-editor":
|
||||
this.selectLeftEditor(message);
|
||||
break;
|
||||
case "select-right-editor":
|
||||
this.selectRightEditor(message);
|
||||
break;
|
||||
case "move-session-left":
|
||||
this.moveSessionLeft(message);
|
||||
break;
|
||||
case "move-session-right":
|
||||
this.moveSessionRight(message);
|
||||
break;
|
||||
case "set-active-editor":
|
||||
this.setActiveEditor(message);
|
||||
break;
|
||||
case "set-tab-to-editor":
|
||||
this.setTabToEditor(message);
|
||||
break;
|
||||
case "close-tab":
|
||||
this.closeTab(message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (message.action === "select-left-editor") {
|
||||
let editorComponent = this.editorsService.get(message.editorUUID);
|
||||
if (!editorComponent.leftSiblingUUID) return;
|
||||
let siblingComponent = this.editorsService.get(editorComponent.leftSiblingUUID);
|
||||
siblingComponent.editor.focus()
|
||||
} else if (message.action === "select-right-editor") {
|
||||
let editorComponent = this.editorsService.get(message.editorUUID);
|
||||
if (!editorComponent.rightSiblingUUID) return;
|
||||
let siblingComponent = this.editorsService.get(editorComponent.rightSiblingUUID);
|
||||
siblingComponent.editor.focus()
|
||||
} else if (message.action === "move-session-left") {
|
||||
let editorComponent = this.editorsService.get(message.editorUUID);
|
||||
if (!editorComponent.leftSiblingUUID) return;
|
||||
|
||||
let siblingComponent = this.editorsService.get(editorComponent.leftSiblingUUID);
|
||||
let session = editorComponent.editor.getSession();
|
||||
let siblingSession = siblingComponent.editor.getSession();
|
||||
|
||||
if (session == siblingSession) return;
|
||||
|
||||
siblingComponent.assignSession(editorComponent.activeFile);
|
||||
|
||||
let targetPath = this.tabsService.getRightSiblingTab(
|
||||
editorComponent.activeFile.path
|
||||
)
|
||||
if (targetPath) {
|
||||
editorComponent.assignSession(
|
||||
this.filesService.get(targetPath)
|
||||
);
|
||||
} else {
|
||||
editorComponent.newFile();
|
||||
}
|
||||
|
||||
siblingComponent.editor.focus()
|
||||
} else if (message.action === "move-session-right") {
|
||||
let editorComponent = this.editorsService.get(message.editorUUID);
|
||||
if (!editorComponent.rightSiblingUUID) return;
|
||||
|
||||
let siblingComponent = this.editorsService.get(editorComponent.rightSiblingUUID);
|
||||
let session = editorComponent.editor.getSession();
|
||||
let siblingSession = siblingComponent.editor.getSession();
|
||||
|
||||
if (session == siblingSession) return;
|
||||
|
||||
siblingComponent.assignSession(editorComponent.activeFile);
|
||||
|
||||
let targetPath = this.tabsService.getRightSiblingTab(
|
||||
editorComponent.activeFile.path
|
||||
)
|
||||
if (targetPath) {
|
||||
editorComponent.assignSession(
|
||||
this.filesService.get(targetPath)
|
||||
);
|
||||
} else {
|
||||
editorComponent.newFile();
|
||||
}
|
||||
|
||||
siblingComponent.editor.focus()
|
||||
} else if (message.action === "set-active-editor") {
|
||||
this.editorsService.getActiveEditorComponent().removeActiveStyling();
|
||||
this.editorsService.setActiveEditor(message.editorUUID);
|
||||
this.editorsService.getActiveEditorComponent().addActiveStyling();
|
||||
} else if (message.action === "set-tab-to-editor") {
|
||||
let file = this.filesService.get(message.filePath);
|
||||
let editorComponent = this.editorsService.getActiveEditorComponent();
|
||||
let editor = editorComponent.editor;
|
||||
|
||||
editorComponent.assignSession(file);
|
||||
this.editorsService.miniMapView.cloneSession(file);
|
||||
} else if (message.action === "close-tab") {
|
||||
let activeComponent = this.editorsService.getActiveEditorComponent();
|
||||
let editors = this.editorsService.getEditorsAsArray();
|
||||
let file = this.filesService.get(message.filePath);
|
||||
|
||||
for (let i = 0; i < editors.length; i++) {
|
||||
let editorComponent = editors[i];
|
||||
if (editorComponent.editor.session == file.session) {
|
||||
if (activeComponent == editorComponent) {
|
||||
this.editorsService.miniMapView.newFile();
|
||||
}
|
||||
editorComponent.newFile();
|
||||
}
|
||||
}
|
||||
|
||||
this.filesService.delete(file);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private loadMainSubscribers() {
|
||||
window?.main.onMenuActions(async (action: string) => {
|
||||
window.fs.onLoadFiles(async (paths: []) => {
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
let file = new File([], "") as NewtonFile;
|
||||
|
||||
if ( this.filesService.get(paths[i]) ) continue;
|
||||
|
||||
await this.filesService.addFile(paths[i], file);
|
||||
this.filesService.addTab(file);
|
||||
}
|
||||
|
||||
let path = paths[ paths.length - 1 ];
|
||||
let file = this.filesService.get(path);
|
||||
this.editorsService.setSession(file);
|
||||
});
|
||||
|
||||
window.fs.onChangedFile(async (path: string, data: string) => {
|
||||
let file = this.filesService.get(path);
|
||||
file.session.setValue(data);
|
||||
|
||||
// Note: fake 'save' event to not show as changed iven external save happened...
|
||||
let message = new ServiceMessage();
|
||||
message.action = "file-saved";
|
||||
message.filePath = path;
|
||||
|
||||
this.tabsService.sendMessage(message);
|
||||
});
|
||||
|
||||
window.fs.onDeletedFile(async (path: string) => {
|
||||
let message = new ServiceMessage();
|
||||
message.action = "file-deleted";
|
||||
message.filePath = path;
|
||||
|
||||
this.tabsService.sendMessage(message);
|
||||
this.filesService.sendMessage(message);
|
||||
});
|
||||
|
||||
window.fs.onSavedFile(async (path: string) => {
|
||||
let message = new ServiceMessage();
|
||||
message.action = "file-saved";
|
||||
message.filePath = path;
|
||||
|
||||
this.tabsService.sendMessage(message);
|
||||
});
|
||||
|
||||
window.fs.onUpdateFilePath(async (path: string) => {
|
||||
console.log(path);
|
||||
// this.tabsService.sendMessage(message);
|
||||
// this.filesService.sendMessage(message);
|
||||
});
|
||||
|
||||
window.main.onMenuActions(async (action: string) => {
|
||||
let editorComponent = this.editorsService.getActiveEditorComponent();
|
||||
let editor = editorComponent.editor;
|
||||
|
||||
@@ -111,65 +232,10 @@ export class EditorsComponent {
|
||||
editor.showSettingsMenu();
|
||||
case "show-about":
|
||||
break;
|
||||
case "quit":
|
||||
window?.main.quit();
|
||||
break;
|
||||
default:
|
||||
editor.execCommand(action);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
window?.fs.onLoadFiles(async (paths: []) => {
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
let file = new File([], "") as NewtonFile;
|
||||
|
||||
if ( this.filesService.get(paths[i]) ) continue;
|
||||
|
||||
await this.filesService.addFile(paths[i], file);
|
||||
this.filesService.addTab(file);
|
||||
}
|
||||
|
||||
let path = paths[ paths.length - 1 ];
|
||||
let file = this.filesService.get(path);
|
||||
this.editorsService.setSession(file);
|
||||
});
|
||||
|
||||
window?.fs.onChangedFile(async (path: string, data: string) => {
|
||||
let file = this.filesService.get(path);
|
||||
file.session.setValue(data);
|
||||
|
||||
// Note: fake 'save' event to not show as changed iven external save happened...
|
||||
let message = new ServiceMessage();
|
||||
message.action = "file-saved";
|
||||
message.filePath = path;
|
||||
|
||||
this.tabsService.sendMessage(message);
|
||||
});
|
||||
|
||||
window?.fs.onDeletedFile(async (path: string) => {
|
||||
let message = new ServiceMessage();
|
||||
message.action = "file-deleted";
|
||||
message.filePath = path;
|
||||
|
||||
this.tabsService.sendMessage(message);
|
||||
this.filesService.sendMessage(message);
|
||||
});
|
||||
|
||||
window?.fs.onSavedFile(async (path: string) => {
|
||||
let message = new ServiceMessage();
|
||||
message.action = "file-saved";
|
||||
message.filePath = path;
|
||||
|
||||
this.tabsService.sendMessage(message);
|
||||
});
|
||||
|
||||
window?.fs.onUpdateFilePath(async (path: string) => {
|
||||
console.log("TODO (onUpdateFilePath) :", path);
|
||||
// this.tabsService.sendMessage(message);
|
||||
// this.filesService.sendMessage(message);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected onFileDropped(files: any) {
|
||||
@@ -182,104 +248,4 @@ export class EditorsComponent {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private selectLeftEditor(message: ServiceMessage) {
|
||||
let editorComponent = this.editorsService.get(message.editorUUID);
|
||||
if (!editorComponent.leftSiblingUUID) return;
|
||||
let siblingComponent = this.editorsService.get(editorComponent.leftSiblingUUID);
|
||||
siblingComponent.editor.focus();
|
||||
}
|
||||
|
||||
private selectRightEditor(message: ServiceMessage) {
|
||||
let editorComponent = this.editorsService.get(message.editorUUID);
|
||||
if (!editorComponent.rightSiblingUUID) return;
|
||||
let siblingComponent = this.editorsService.get(editorComponent.rightSiblingUUID);
|
||||
siblingComponent.editor.focus();
|
||||
}
|
||||
|
||||
private moveSessionLeft(message: ServiceMessage) {
|
||||
let editorComponent = this.editorsService.get(message.editorUUID);
|
||||
if (!editorComponent.leftSiblingUUID) return;
|
||||
|
||||
let siblingComponent = this.editorsService.get(editorComponent.leftSiblingUUID);
|
||||
this.moveSession("left", editorComponent, siblingComponent);
|
||||
}
|
||||
|
||||
private moveSessionRight(message: ServiceMessage) {
|
||||
let editorComponent = this.editorsService.get(message.editorUUID);
|
||||
if (!editorComponent.rightSiblingUUID) return;
|
||||
|
||||
let siblingComponent = this.editorsService.get(editorComponent.rightSiblingUUID);
|
||||
this.moveSession("right", editorComponent, siblingComponent);
|
||||
}
|
||||
|
||||
private moveSession(
|
||||
direction: string,
|
||||
editorComponent: CodeViewComponent,
|
||||
siblingComponent: CodeViewComponent
|
||||
) {
|
||||
let session = editorComponent.editor.getSession();
|
||||
let siblingSession = siblingComponent.editor.getSession();
|
||||
|
||||
if (session == siblingSession) return;
|
||||
|
||||
let targetPath: string = this.tabsService.getRightSiblingTab(
|
||||
editorComponent.activeFile.path
|
||||
);
|
||||
|
||||
siblingComponent.assignSession(editorComponent.activeFile);
|
||||
if (targetPath) {
|
||||
editorComponent.assignSession(
|
||||
this.filesService.get(targetPath)
|
||||
);
|
||||
} else {
|
||||
editorComponent.newFile();
|
||||
}
|
||||
|
||||
siblingComponent.editor.focus()
|
||||
}
|
||||
|
||||
|
||||
private setActiveEditor(message: ServiceMessage) {
|
||||
this.editorsService.getActiveEditorComponent().removeActiveStyling();
|
||||
this.editorsService.setActiveEditor(message.editorUUID);
|
||||
this.editorsService.getActiveEditorComponent().addActiveStyling();
|
||||
}
|
||||
private setTabToEditor(message: ServiceMessage) {
|
||||
let file = this.filesService.get(message.filePath);
|
||||
let editorComponent = this.editorsService.getActiveEditorComponent();
|
||||
let editor = editorComponent.editor;
|
||||
|
||||
editorComponent.assignSession(file);
|
||||
this.editorsService.miniMapView.cloneSession(file);
|
||||
}
|
||||
|
||||
private closeTab(message: ServiceMessage) {
|
||||
let activeComponent = this.editorsService.getActiveEditorComponent();
|
||||
let editors = this.editorsService.getEditorsAsArray();
|
||||
let file = this.filesService.get(message.filePath);
|
||||
|
||||
for (let i = 0; i < editors.length; i++) {
|
||||
let editorComponent = editors[i];
|
||||
|
||||
if (editorComponent.editor.session !== file.session) continue;
|
||||
|
||||
let targetFile = this.filesService.getPreviousFile(file.path)
|
||||
if (targetFile && (targetFile.path !== message.filePath)) {
|
||||
editorComponent.assignSession(targetFile);
|
||||
if (activeComponent == editorComponent) {
|
||||
this.editorsService.miniMapView.cloneSession(targetFile);
|
||||
}
|
||||
} else {
|
||||
editorComponent.newFile();
|
||||
if (activeComponent == editorComponent) {
|
||||
this.editorsService.miniMapView.newFile();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
activeComponent.lspManagerService.closeDocument(file.session);
|
||||
this.filesService.unset(file);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, DestroyRef, inject } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
import { InfoBarService } from '../../common/services/editor/info-bar/info-bar.service';
|
||||
|
||||
@@ -17,7 +17,7 @@ import { InfoBarService } from '../../common/services/editor/info-bar/info-bar.s
|
||||
}
|
||||
})
|
||||
export class InfoBarComponent {
|
||||
readonly #destroyRef: DestroyRef = inject(DestroyRef);
|
||||
private unsubscribe: Subject<void> = new Subject();
|
||||
|
||||
private infoBarService: InfoBarService = inject(InfoBarService);
|
||||
|
||||
@@ -28,14 +28,18 @@ export class InfoBarComponent {
|
||||
ftype: string = "";
|
||||
|
||||
|
||||
constructor() {
|
||||
constructor() {}
|
||||
|
||||
|
||||
private ngAfterViewInit(): void {
|
||||
this.loadSubscribers();
|
||||
}
|
||||
|
||||
|
||||
private loadSubscribers() {
|
||||
|
||||
this.infoBarService.updateInfoBarFPath$().pipe(
|
||||
takeUntilDestroyed(this.#destroyRef)
|
||||
takeUntil(this.unsubscribe)
|
||||
).subscribe((fpath: string) => {
|
||||
this.fpath = fpath;
|
||||
let _path = fpath;
|
||||
@@ -48,19 +52,19 @@ export class InfoBarComponent {
|
||||
});
|
||||
|
||||
this.infoBarService.updateInfoBarCursorPos$().pipe(
|
||||
takeUntilDestroyed(this.#destroyRef)
|
||||
takeUntil(this.unsubscribe)
|
||||
).subscribe((cursorPos: any) => {
|
||||
this.cursorPos = `${cursorPos.row + 1}:${cursorPos.column}`;
|
||||
});
|
||||
|
||||
this.infoBarService.updateInfoBarEncodeing$().pipe(
|
||||
takeUntilDestroyed(this.#destroyRef)
|
||||
takeUntil(this.unsubscribe)
|
||||
).subscribe((encodeing: string) => {
|
||||
this.encodeing = encodeing;
|
||||
});
|
||||
|
||||
this.infoBarService.updateInfoBarFType$().pipe(
|
||||
takeUntilDestroyed(this.#destroyRef)
|
||||
takeUntil(this.unsubscribe)
|
||||
).subscribe((ftype: string) => {
|
||||
let mode = ftype.split("/");
|
||||
this.ftype = mode[ mode.length - 1 ];
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
<div class="row mt-2 mb-3">
|
||||
|
||||
<div class="col clear-right-padding">
|
||||
<div class="input-group-sm"
|
||||
(mouseup)="handleActionMouseUp($event)"
|
||||
>
|
||||
<div class="input-group-sm">
|
||||
<label class="form-control" [innerText]="lspManagerService.workspaceFolder || 'Project Path...'">
|
||||
</label>
|
||||
</div>
|
||||
@@ -37,21 +35,9 @@
|
||||
</div>
|
||||
|
||||
<div class="row mt-2 md-2">
|
||||
<div class="col col-sm" [hidden]="!lspManagerService.workspaceFolder">
|
||||
<button class="btn btn-sm btn-dark" (click)="createLanguageClient()">Create Language Client</button>
|
||||
<button class="btn btn-sm btn-dark" (click)="closeLanguageClient()">Close Language Client</button>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
Target Editor: <label [innerText]="editor?.id || '...'"></label>
|
||||
Target Editor: <label [innerText]="editor?.id || 'Editor...'"></label>
|
||||
</div>
|
||||
<div class="col-sm" [hidden]="!lspManagerService.workspaceFolder">
|
||||
<button class="btn btn-sm btn-dark"
|
||||
(click)="registerEditorToLanguageClient()">
|
||||
Register Editor To LSP
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
Active Editor Session:
|
||||
</div>
|
||||
@@ -66,12 +52,3 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<ul #contextMenu
|
||||
class="contextMenu"
|
||||
[hidden]="!showContextMenu"
|
||||
(blur)="hideContextMenu"
|
||||
(click)="contextMenuClicked($event)"
|
||||
>
|
||||
<li command="pasteText">Paste</li>
|
||||
</ul>
|
||||
@@ -1,12 +1,5 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectorRef,
|
||||
DestroyRef,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
ViewChild,
|
||||
inject } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Component, ChangeDetectorRef, ElementRef, HostBinding, ViewChild, inject } from '@angular/core';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
import { LspManagerService } from '../../common/services/editor/lsp-manager/lsp-manager.service';
|
||||
|
||||
@@ -14,8 +7,6 @@ import { CodeViewComponent } from '../code-view/view.component';
|
||||
|
||||
import { ServiceMessage } from '../../common/types/service-message.type';
|
||||
|
||||
import { ButtonMap } from '../../common/constants/button.map';
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
@@ -32,8 +23,8 @@ import { ButtonMap } from '../../common/constants/button.map';
|
||||
}
|
||||
})
|
||||
export class LspManagerComponent {
|
||||
readonly #destroyRef = inject(DestroyRef);
|
||||
private changeDetectorRef: ChangeDetectorRef = inject(ChangeDetectorRef);
|
||||
private unsubscribe: Subject<void> = new Subject();
|
||||
private changeDetectorRef: ChangeDetectorRef = inject(ChangeDetectorRef);
|
||||
|
||||
lspManagerService: LspManagerService = inject(LspManagerService);
|
||||
|
||||
@@ -43,117 +34,55 @@ export class LspManagerComponent {
|
||||
lspTextEditor: any;
|
||||
innerEditor: any;
|
||||
editor: any;
|
||||
activeFile: any;
|
||||
|
||||
@ViewChild('contextMenu') contextMenu!: ElementRef;
|
||||
public showContextMenu: boolean = false;
|
||||
|
||||
|
||||
|
||||
constructor() {
|
||||
this.loadSubscribers();
|
||||
}
|
||||
|
||||
|
||||
private ngAfterViewInit(): void {
|
||||
this.mapEditorsAndLoadConfig();
|
||||
}
|
||||
|
||||
private mapEditorsAndLoadConfig() {
|
||||
this.lspTextEditor = this.lspEditorComponent.editor;
|
||||
this.innerEditor = this.sessionEditorComponent.editor;
|
||||
|
||||
this.lspTextEditor.on("input", () => {
|
||||
this.lspManagerService.lspConfigDataStr =
|
||||
this.lspTextEditor.session.getValue();
|
||||
});
|
||||
|
||||
this.lspManagerService.loadLspConfigData().then((lspConfigData) => {
|
||||
this.lspTextEditor.session.setMode("ace/mode/json");
|
||||
this.lspTextEditor.session.setValue(lspConfigData);
|
||||
});
|
||||
|
||||
this.loadSubscribers();
|
||||
}
|
||||
|
||||
private ngOnDestroy() {
|
||||
this.unsubscribe.next();
|
||||
this.unsubscribe.complete();
|
||||
}
|
||||
|
||||
private loadSubscribers() {
|
||||
this.lspManagerService.getMessage$().pipe(
|
||||
takeUntilDestroyed(this.#destroyRef)
|
||||
takeUntil(this.unsubscribe)
|
||||
).subscribe((message: ServiceMessage) => {
|
||||
if (message.action === "toggle-lsp-manager") {
|
||||
this.toggleLspManager(message);
|
||||
} else if (message.action === "set-active-editor") {
|
||||
this.setActiveEditor(message);
|
||||
} else if (message.action === "editor-update") {
|
||||
this.editorUpdate(message);
|
||||
} else if (message.action === "close-file") {
|
||||
this.closeFile(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected handleActionMouseUp(event: any): void {
|
||||
if (ButtonMap.LEFT === event.button) return;
|
||||
|
||||
let target = event.target;
|
||||
|
||||
let menuElm = this.contextMenu.nativeElement;
|
||||
let pageX = event.clientX;
|
||||
let pageY = event.clientY;
|
||||
|
||||
const origin = {
|
||||
left: pageX + 5,
|
||||
top: pageY - 5
|
||||
};
|
||||
|
||||
menuElm.style.left = `${origin.left}px`;
|
||||
menuElm.style.top = `${origin.top}px`;
|
||||
this.showContextMenu = true;
|
||||
}
|
||||
|
||||
public hideContextMenu() {
|
||||
this.showContextMenu = false;
|
||||
}
|
||||
|
||||
public contextMenuClicked(event: any) {
|
||||
this.showContextMenu = false;
|
||||
|
||||
const command = event.target.getAttribute("command");
|
||||
const args = event.target.getAttribute("args");
|
||||
|
||||
if (!command) return;
|
||||
|
||||
this[command]( (args) ? args : null );
|
||||
}
|
||||
|
||||
public pasteText() {
|
||||
navigator.clipboard.readText().then((pasteText) => {
|
||||
if (pasteText.includes("\n") || !pasteText.startsWith("/")) return;
|
||||
this.lspManagerService.workspaceFolder = pasteText;
|
||||
});
|
||||
}
|
||||
|
||||
public clearWorkspaceFolder() {
|
||||
this.lspManagerService.workspaceFolder = "";
|
||||
}
|
||||
|
||||
public setWorkspaceFolder() {
|
||||
window?.fs.chooseFolder().then((folder: string) => {
|
||||
window.fs.chooseFolder().then((folder: string) => {
|
||||
if (!folder) return;
|
||||
|
||||
this.lspManagerService.workspaceFolder = folder;
|
||||
});
|
||||
}
|
||||
|
||||
public createLanguageClient() {
|
||||
let mode = this.lspManagerService.getMode(this.editor.session);
|
||||
this.lspManagerService.createLanguageProviderWithClientServer(mode);
|
||||
}
|
||||
|
||||
public closeLanguageClient() {
|
||||
let mode = this.lspManagerService.getMode(this.editor.session);
|
||||
this.lspManagerService.closeLanguageProviderWithClientServer(mode);
|
||||
}
|
||||
|
||||
public registerEditorToLanguageClient() {
|
||||
this.lspManagerService.registerEditorToLSPClient(this.editor);
|
||||
}
|
||||
|
||||
|
||||
public globalLspManagerKeyHandler(event: any) {
|
||||
@@ -174,33 +103,15 @@ export class LspManagerComponent {
|
||||
|
||||
// Note: hack for issue with setActiveEditor TODO
|
||||
setTimeout(() => {
|
||||
this.innerEditor.setSession(this.editor.getSession());
|
||||
this.innerEditor.setSession(this.editor.session);
|
||||
}, 10);
|
||||
}
|
||||
|
||||
private setActiveEditor(message: ServiceMessage) {
|
||||
this.editor = message.rawData.editor;
|
||||
this.activeFile = message.rawData.activeFile;
|
||||
|
||||
this.editor = message.rawData;
|
||||
// TODO: figure out why this doesn't update the session consistently...
|
||||
// It seems maybe bound to visible state as change detector ref didn't help either.
|
||||
// this.innerEditor.setSession(this.editor.session);
|
||||
}
|
||||
|
||||
private editorUpdate(message: ServiceMessage) {
|
||||
if (
|
||||
!this.editor ||
|
||||
!message.rawData.activeFile
|
||||
) return;
|
||||
|
||||
this.editor.setSession(message.rawData.editor.getSession())
|
||||
this.activeFile = message.rawData.activeFile;
|
||||
|
||||
this.lspManagerService.registerSession(this.editor);
|
||||
}
|
||||
|
||||
private closeFile(message: ServiceMessage) {
|
||||
this.lspManagerService.closeDocument(message.rawData);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
import {
|
||||
Component,
|
||||
DestroyRef,
|
||||
HostBinding,
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
import { marked } from 'marked';
|
||||
import { Component, HostBinding, inject } from '@angular/core';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
import { MarkdownPreviewService } from '../../common/services/editor/markdown-preview/markdown-preview.service';
|
||||
|
||||
@@ -26,12 +19,12 @@ import { ServiceMessage } from '../../common/types/service-message.type';
|
||||
}
|
||||
})
|
||||
export class MarkdownPreviewComponent {
|
||||
readonly #destroyRef: DestroyRef = inject(DestroyRef);
|
||||
private unsubscribe: Subject<void> = new Subject();
|
||||
|
||||
private markdownPreviewService: MarkdownPreviewService = inject(MarkdownPreviewService);
|
||||
|
||||
@HostBinding("class.hidden") isHidden: boolean = true;
|
||||
converter: any = marked;
|
||||
converter: any = new showdown.Converter();
|
||||
defaultHtml: string = "<h1>NOT a Markdown file...</h1>"
|
||||
bodyHtml: string = "";
|
||||
|
||||
@@ -39,22 +32,26 @@ export class MarkdownPreviewComponent {
|
||||
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
private ngAfterViewInit(): void {
|
||||
this.loadSubscribers();
|
||||
}
|
||||
|
||||
private ngOnDestroy() {
|
||||
this.unsubscribe.next();
|
||||
this.unsubscribe.complete();
|
||||
}
|
||||
|
||||
private loadSubscribers() {
|
||||
this.markdownPreviewService.getMessage$().pipe(
|
||||
takeUntilDestroyed(this.#destroyRef)
|
||||
takeUntil(this.unsubscribe)
|
||||
).subscribe((message: ServiceMessage) => {
|
||||
switch ( message.action ) {
|
||||
case "toggle-markdown-preview":
|
||||
this.toggleMarkdownPreview(message);
|
||||
break;
|
||||
case "set-active-editor":
|
||||
this.setActiveEditor(message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (message.action === "toggle-markdown-preview") {
|
||||
this.toggleMarkdownPreview(message);
|
||||
} else if (message.action === "set-active-editor") {
|
||||
this.setActiveEditor(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -87,7 +84,7 @@ export class MarkdownPreviewComponent {
|
||||
let mdStr = this.editorComponent.editor.session.getValue();
|
||||
let pathParts = this.editorComponent.activeFile.path.split("/");
|
||||
let basePath = "file://" + pathParts.slice(0, -1).join("/");
|
||||
this.bodyHtml = this.converter.parse(
|
||||
this.bodyHtml = this.converter.makeHtml(
|
||||
mdStr.replaceAll("](images", `](${basePath}/images`)
|
||||
.replaceAll("](imgs", `](${basePath}/imgs`)
|
||||
.replaceAll("](pictures", `](${basePath}/pictures`)
|
||||
|
||||
@@ -1,21 +1,7 @@
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col col-3">
|
||||
@if (isQueryLong) {
|
||||
<label id="find-status-lbl">
|
||||
<b class="error">Query exceeds 80 characters...</b>
|
||||
</label>
|
||||
} @else if (isQueryNotFound) {
|
||||
<label id="find-status-lbl">
|
||||
<b class="warning">Query not found...</b>
|
||||
</label>
|
||||
} @else if (query && !isQueryLong && !isQueryNotFound) {
|
||||
<label id="find-status-lbl">Found in current file:
|
||||
<b class="success">{{totalCount}}</b>
|
||||
</label>
|
||||
} @else {
|
||||
<label id="find-status-lbl">Find in Current File:</label>
|
||||
}
|
||||
<label id="find-status-lbl">Find in Current File</label>
|
||||
</div>
|
||||
|
||||
<div class="col col-4">
|
||||
@@ -59,27 +45,15 @@
|
||||
id="find-entry"
|
||||
class="form-control"
|
||||
type="search"
|
||||
(focus)="searchForString()"
|
||||
(keyup)="findEntryKeyUpHandler($event)"
|
||||
(input)="searchForString()"
|
||||
(keyup)="searchForString()"
|
||||
placeholder="Find in current file..."
|
||||
aria-label="Find in current file..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-auto">
|
||||
<button
|
||||
[disabled]="!query || isQueryLong || isQueryNotFound"
|
||||
id="find-btn"
|
||||
class="width-8em btn btn-sm btn-dark"
|
||||
(click)="findNextEntry()">Find
|
||||
</button>
|
||||
<button
|
||||
[disabled]="!query || isQueryLong || isQueryNotFound"
|
||||
id="find-all-btn"
|
||||
class="width-8em btn btn-sm btn-dark"
|
||||
(click)="findAllEntries()">Find All
|
||||
</button>
|
||||
<button id="find-btn" class="width-8em btn btn-sm btn-dark" (click)="findNextEntry()">Find</button>
|
||||
<button id="find-all-btn" class="width-8em btn btn-sm btn-dark" (click)="findAllEntries()">Find All</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,25 +68,15 @@
|
||||
id="replace-entry"
|
||||
class="form-control"
|
||||
type="search"
|
||||
(keyup.enter)="replaceEntry($event)"
|
||||
(keyup)="replaceEntry($event)"
|
||||
title="Replace in current file..."
|
||||
placeholder="Replace in current file..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-auto">
|
||||
<button
|
||||
[disabled]="!query || isQueryLong || isQueryNotFound"
|
||||
id="replace-btn"
|
||||
class="width-8em btn btn-sm btn-dark"
|
||||
(click)="replaceEntry($event)">Replace
|
||||
</button>
|
||||
<button
|
||||
[disabled]="!query || isQueryLong || isQueryNotFound"
|
||||
id="replace-all-btn"
|
||||
class="width-8em btn btn-sm btn-dark"
|
||||
(click)="replaceAll()">Replace All
|
||||
</button>
|
||||
<button id="replace-btn" class="width-8em btn btn-sm btn-dark" (click)="replaceEntry($event)">Replace</button>
|
||||
<button id="replace-all-btn" class="width-8em btn btn-sm btn-dark" (click)="replaceAll()">Replace All</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
import {
|
||||
Component,
|
||||
DestroyRef,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
Input,
|
||||
ViewChild,
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Component, ElementRef, HostBinding, Input, ViewChild, inject } from '@angular/core';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
import { SearchReplaceService } from '../../common/services/editor/search-replace/search-replace.service';
|
||||
|
||||
@@ -28,7 +20,7 @@ import { ServiceMessage } from '../../common/types/service-message.type';
|
||||
}
|
||||
})
|
||||
export class SearchReplaceComponent {
|
||||
readonly #destroyRef: DestroyRef = inject(DestroyRef);
|
||||
private unsubscribe: Subject<void> = new Subject();
|
||||
|
||||
private searchReplaceService: SearchReplaceService = inject(SearchReplaceService);
|
||||
|
||||
@@ -36,19 +28,15 @@ export class SearchReplaceComponent {
|
||||
@ViewChild('findEntryElm') findEntryElm!: ElementRef;
|
||||
@ViewChild('replaceEntryElm') replaceEntryElm!: ElementRef;
|
||||
|
||||
@Input() query: string = "";
|
||||
@Input() findOptions: string = "";
|
||||
@Input() isQueryLong: boolean = false;
|
||||
@Input() isQueryNotFound: boolean = false;
|
||||
@Input() totalCount: number = 0;
|
||||
|
||||
private editor!: any;
|
||||
|
||||
@Input() findOptions: string = "";
|
||||
private useWholeWordSearch: boolean = false;
|
||||
private searchOnlyInSelection: boolean = false;
|
||||
private useCaseSensitive: boolean = false;
|
||||
private useRegex: boolean = false;
|
||||
private selection: string = "";
|
||||
private query: string = "";
|
||||
private toStr: string = "";
|
||||
private isBackwards: boolean = false;
|
||||
private isWrap: boolean = true;
|
||||
@@ -57,22 +45,26 @@ export class SearchReplaceComponent {
|
||||
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
private ngAfterViewInit(): void {
|
||||
this.loadSubscribers();
|
||||
}
|
||||
|
||||
private ngOnDestroy() {
|
||||
this.unsubscribe.next();
|
||||
this.unsubscribe.complete();
|
||||
}
|
||||
|
||||
private loadSubscribers() {
|
||||
this.searchReplaceService.getMessage$().pipe(
|
||||
takeUntilDestroyed(this.#destroyRef)
|
||||
takeUntil(this.unsubscribe)
|
||||
).subscribe((message: ServiceMessage) => {
|
||||
switch ( message.action ) {
|
||||
case "toggle-search-replace":
|
||||
this.toggleSearchReplace(message);
|
||||
break;
|
||||
case "set-active-editor":
|
||||
this.setActiveEditor(message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (message.action === "toggle-search-replace") {
|
||||
this.toggleSearchReplace(message);
|
||||
} else if (message.action === "set-active-editor") {
|
||||
this.setActiveEditor(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -183,25 +175,17 @@ export class SearchReplaceComponent {
|
||||
this.findOptions = findOptionsStr;
|
||||
}
|
||||
|
||||
public findPreviousEntry() {
|
||||
this.editor.findPrevious();
|
||||
}
|
||||
|
||||
public findNextEntry() {
|
||||
this.editor.findNext();
|
||||
}
|
||||
|
||||
public findEntryKeyUpHandler(event: KeyboardEvent) {
|
||||
if (!event.ctrlKey || !this.query) return;
|
||||
|
||||
if (event.key === "ArrowUp") this.findPreviousEntry();
|
||||
if (event.key === "ArrowDown") this.findNextEntry();
|
||||
}
|
||||
|
||||
public findAllEntries() {
|
||||
this.query = this.findEntryElm.nativeElement.value;
|
||||
|
||||
this.totalCount = this.editor.findAll(this.query, {
|
||||
if (!this.query) return;
|
||||
|
||||
let totalCount = this.editor.findAll(this.query, {
|
||||
backwards: this.isBackwards,
|
||||
wrap: this.isWrap,
|
||||
caseSensitive: this.useCaseSensitive,
|
||||
@@ -209,19 +193,25 @@ export class SearchReplaceComponent {
|
||||
regExp: this.useRegex,
|
||||
range: this.searchOnlyInSelection
|
||||
});
|
||||
|
||||
if (this.totalCount === 0) this.isQueryNotFound = true;
|
||||
}
|
||||
|
||||
public replaceEntry(event: KeyboardEvent) {
|
||||
if (this.isQueryLong || this.isQueryNotFound) return;
|
||||
public findPreviousEntry() {
|
||||
this.editor.findPrevious();
|
||||
}
|
||||
|
||||
public replaceEntry(event: any) {
|
||||
if (event instanceof KeyboardEvent) {
|
||||
if (event.key !== "Enter") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let fromStr = this.findEntryElm.nativeElement.value;
|
||||
let toStr = this.replaceEntryElm.nativeElement.value;
|
||||
|
||||
if (!fromStr) return;
|
||||
|
||||
this.editor.replace(toStr, fromStr, {
|
||||
let totalCount = this.editor.replace(toStr, fromStr, {
|
||||
backwards: this.isBackwards,
|
||||
wrap: this.isWrap,
|
||||
caseSensitive: this.useCaseSensitive,
|
||||
@@ -235,14 +225,12 @@ export class SearchReplaceComponent {
|
||||
}
|
||||
|
||||
public replaceAll() {
|
||||
if (this.isQueryLong || this.isQueryNotFound) return;
|
||||
|
||||
let fromStr = this.findEntryElm.nativeElement.value;
|
||||
let toStr = this.replaceEntryElm.nativeElement.value;
|
||||
|
||||
if (!fromStr) return;
|
||||
|
||||
this.editor.replaceAll(toStr, fromStr, {
|
||||
let totalCount = this.editor.replaceAll(toStr, fromStr, {
|
||||
backwards: this.isBackwards,
|
||||
wrap: this.isWrap,
|
||||
caseSensitive: this.useCaseSensitive,
|
||||
@@ -250,27 +238,23 @@ export class SearchReplaceComponent {
|
||||
regExp: this.useRegex,
|
||||
range: this.searchOnlyInSelection
|
||||
});
|
||||
|
||||
this.isQueryNotFound = true;
|
||||
}
|
||||
|
||||
public searchForString() {
|
||||
if (this.searchTimeoutId) { clearTimeout(this.searchTimeoutId); }
|
||||
if (event instanceof KeyboardEvent) {
|
||||
if (event.key !== "Enter") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.query = this.findEntryElm.nativeElement.value;
|
||||
|
||||
if (!this.query) {
|
||||
this.isQueryLong = false;
|
||||
this.isQueryNotFound = false;
|
||||
if (!this.query) return;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.isQueryLong = (this.query.length > 80);
|
||||
if (this.isQueryLong) return;
|
||||
if (this.searchTimeoutId) { clearTimeout(this.searchTimeoutId); }
|
||||
|
||||
this.searchTimeoutId = setTimeout(() => {
|
||||
this.totalCount = this.editor.findAll(this.query, {
|
||||
let totalCount = this.editor.find(this.query, {
|
||||
backwards: this.isBackwards,
|
||||
wrap: this.isWrap,
|
||||
caseSensitive: this.useCaseSensitive,
|
||||
@@ -278,8 +262,6 @@ export class SearchReplaceComponent {
|
||||
regExp: this.useRegex,
|
||||
range: this.searchOnlyInSelection
|
||||
});
|
||||
|
||||
this.isQueryNotFound = (this.totalCount === 0);
|
||||
}, this.searchTimeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
}
|
||||
|
||||
.active-tab {
|
||||
background-color: rgba(144, 144, 144, 0.64);
|
||||
background-color: rgba(255, 255, 255, 0.46);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
font-size: 4em;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
cdkDropListLockAxis="x"
|
||||
cdkDropListOrientation="horizontal"
|
||||
(cdkDropListDropped)="dropped($event)"
|
||||
(mousedown)="handleActionMouseDown($event)"
|
||||
(click)="handleActionClick($event)"
|
||||
(click)="handleAction($event)"
|
||||
class="display-contents"
|
||||
>
|
||||
|
||||
@@ -21,15 +20,3 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<ul #contextMenu
|
||||
class="contextMenu"
|
||||
[hidden]="!showContextMenu"
|
||||
(blur)="hideContextMenu()"
|
||||
(click)="contextMenuClicked($event)"
|
||||
>
|
||||
<li command="close">Close</li>
|
||||
<li command="closeAll">Close All</li>
|
||||
<li command="closeAllLeft">Close All Left</li>
|
||||
<li command="closeAllRight">Close All Right</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectorRef,
|
||||
DestroyRef,
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import { Component, ChangeDetectorRef, inject } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CdkDrag, CdkDragDrop, CdkDropList } from '@angular/cdk/drag-drop';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
import { TabsService } from '../../common/services/editor/tabs/tabs.service';
|
||||
|
||||
import { ServiceMessage } from '../../common/types/service-message.type';
|
||||
|
||||
import { ButtonMap } from '../../common/constants/button.map';
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
@@ -33,129 +24,68 @@ import { ButtonMap } from '../../common/constants/button.map';
|
||||
}
|
||||
})
|
||||
export class TabsComponent {
|
||||
readonly #destroyRef = inject(DestroyRef);
|
||||
private unsubscribe: Subject<void> = new Subject();
|
||||
|
||||
private tabsService: TabsService = inject(TabsService);
|
||||
private changeDetectorRef: ChangeDetectorRef = inject(ChangeDetectorRef);
|
||||
|
||||
@ViewChild('contextMenu') contextMenu!: ElementRef;
|
||||
public showContextMenu: boolean = false;
|
||||
|
||||
tabs: any[] = this.tabsService.tabs;
|
||||
targetEvent!: any;
|
||||
activeTab!: any;
|
||||
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
private ngAfterViewInit(): void {
|
||||
this.loadSubscribers();
|
||||
}
|
||||
|
||||
private ngOnDestroy(): void {
|
||||
this.unsubscribe.next();
|
||||
this.unsubscribe.complete();
|
||||
}
|
||||
|
||||
private loadSubscribers() {
|
||||
this.tabsService.getMessage$().pipe(
|
||||
takeUntilDestroyed(this.#destroyRef)
|
||||
takeUntil(this.unsubscribe)
|
||||
).subscribe((message: ServiceMessage) => {
|
||||
let elm = document.querySelector(`.tab[title="${message.filePath}"]`);
|
||||
|
||||
switch ( message.action ) {
|
||||
case "create-tab":
|
||||
this.createTab(message.fileName, message.fileUUID, message.filePath);
|
||||
break;
|
||||
case "file-unmodified":
|
||||
elm.classList.remove("file-changed");
|
||||
break;
|
||||
case "file-changed":
|
||||
elm.classList.add("file-changed");
|
||||
elm.classList.remove("file-deleted");
|
||||
break;
|
||||
case "file-deleted":
|
||||
elm.classList.add("file-deleted");
|
||||
elm.classList.remove("file-changed");
|
||||
break;
|
||||
case "file-saved":
|
||||
elm.classList.remove("file-deleted");
|
||||
elm.classList.remove("file-changed");
|
||||
break;
|
||||
case "highlight-active-tab":
|
||||
if (!elm) {
|
||||
if (this.activeTab) {
|
||||
this.activeTab.classList.remove("active-tab")
|
||||
this.activeTab = elm;
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
if (this.activeTab) {
|
||||
if (
|
||||
this.activeTab.getAttribute("title") == elm.getAttribute("title")
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.activeTab.classList.remove("active-tab")
|
||||
}
|
||||
|
||||
this.activeTab = elm;
|
||||
elm.classList.add("active-tab");
|
||||
elm.scrollIntoView(
|
||||
{
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
inline: "center"
|
||||
}
|
||||
);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (message.action === "create-tab") {
|
||||
this.createTab(message.fileName, message.fileUUID, message.filePath);
|
||||
} else if (message.action === "file-changed") {
|
||||
let elm = document.querySelectorAll(`[title="${message.filePath}"]`)[1];
|
||||
elm.classList.add("file-changed");
|
||||
elm.classList.remove("file-deleted");
|
||||
} else if (message.action === "file-deleted") {
|
||||
let elm = document.querySelectorAll(`[title="${message.filePath}"]`)[1];
|
||||
elm.classList.add("file-deleted");
|
||||
elm.classList.remove("file-changed");
|
||||
} else if (message.action === "file-saved") {
|
||||
let elm = document.querySelectorAll(`[title="${message.filePath}"]`)[1];
|
||||
elm.classList.remove("file-deleted");
|
||||
elm.classList.remove("file-changed");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
protected handleActionClick(event: any): void {
|
||||
if (ButtonMap.RIGHT === event.button) return;
|
||||
|
||||
protected handleAction(event: any): void {
|
||||
let target = event.target;
|
||||
|
||||
this.showContextMenu = false;
|
||||
this.processTargetEvent(event);
|
||||
}
|
||||
if ( target.classList.contains("tab") ) {
|
||||
this.tabsService.sendEditorsServiceAMessage(
|
||||
"set-tab-to-editor",
|
||||
event.srcElement.getAttribute("title")
|
||||
);
|
||||
|
||||
protected handleActionMouseDown(event: any): void {
|
||||
if (ButtonMap.LEFT === event.button) return;
|
||||
} else if ( target.classList.contains("title") ) {
|
||||
this.tabsService.sendEditorsServiceAMessage(
|
||||
"set-tab-to-editor",
|
||||
event.srcElement.parentElement.getAttribute("title")
|
||||
);
|
||||
} else if ( target.classList.contains("close-button") ) {
|
||||
this.tabsService.closeTab(
|
||||
event.srcElement.parentElement.getAttribute("title")
|
||||
);
|
||||
}
|
||||
|
||||
let target = event.target;
|
||||
|
||||
let menuElm = this.contextMenu.nativeElement;
|
||||
let pageX = event.clientX;
|
||||
let pageY = event.clientY;
|
||||
|
||||
const origin = {
|
||||
left: pageX + 5,
|
||||
top: pageY - 5
|
||||
};
|
||||
|
||||
menuElm.style.left = `${origin.left}px`;
|
||||
menuElm.style.top = `${origin.top}px`;
|
||||
this.targetEvent = event;
|
||||
this.showContextMenu = true;
|
||||
}
|
||||
|
||||
public hideContextMenu() {
|
||||
this.showContextMenu = false;
|
||||
}
|
||||
|
||||
public contextMenuClicked(event: any) {
|
||||
this.showContextMenu = false;
|
||||
|
||||
const command = event.target.getAttribute("command");
|
||||
const args = event.target.getAttribute("args");
|
||||
|
||||
if (!command) return;
|
||||
|
||||
this[command]( (args) ? args : null );
|
||||
}
|
||||
|
||||
public createTab(title: string, uuid: string, path: string): void {
|
||||
@@ -182,87 +112,4 @@ export class TabsComponent {
|
||||
this.tabsService.move(event.previousIndex);
|
||||
}
|
||||
|
||||
|
||||
private close(event: any): void {
|
||||
this.tabsService.closeTab(
|
||||
this.targetEvent.srcElement.parentElement.getAttribute("title")
|
||||
);
|
||||
}
|
||||
|
||||
private closeAll(event: any): void {
|
||||
let elm = this.targetEvent.srcElement.parentElement;
|
||||
let startElm = elm;
|
||||
|
||||
// clear right
|
||||
while (elm) {
|
||||
elm = elm.nextSibling;
|
||||
if (!elm || elm.nodeType == 8) continue;
|
||||
|
||||
this.tabsService.closeTab( elm.getAttribute("title") );
|
||||
}
|
||||
|
||||
// clear left
|
||||
elm = startElm;
|
||||
while (elm) {
|
||||
elm = elm.previousSibling;
|
||||
if (!elm || elm.nodeType == 8) continue;
|
||||
|
||||
this.tabsService.closeTab( elm.getAttribute("title") );
|
||||
}
|
||||
|
||||
// clear initial target
|
||||
elm = startElm;
|
||||
this.tabsService.closeTab( elm.getAttribute("title") );
|
||||
}
|
||||
|
||||
private closeAllLeft(event: any): void {
|
||||
let elm = this.targetEvent.srcElement.parentElement;
|
||||
|
||||
// clear left
|
||||
while (elm) {
|
||||
elm = elm.previousSibling;
|
||||
if (!elm || elm.nodeType == 8) continue;
|
||||
|
||||
this.tabsService.closeTab( elm.getAttribute("title") );
|
||||
}
|
||||
}
|
||||
|
||||
private closeAllRight(event: any): void {
|
||||
let elm = this.targetEvent.srcElement.parentElement;
|
||||
|
||||
// clear right
|
||||
while (elm) {
|
||||
elm = elm.nextSibling;
|
||||
if (!elm || elm.nodeType == 8) continue;
|
||||
|
||||
this.tabsService.closeTab( elm.getAttribute("title") );
|
||||
}
|
||||
}
|
||||
|
||||
private processTargetEvent(event: any): void {
|
||||
let target = event.target;
|
||||
|
||||
if ( target.classList.contains("tab") ) {
|
||||
let fpath = event.srcElement.getAttribute("title")
|
||||
this.tabsService.sendEditorsServiceAMessage("set-tab-to-editor", fpath);
|
||||
|
||||
// this.updateActiveTabHighlight(fpath);
|
||||
} else if ( target.classList.contains("title") ) {
|
||||
let fpath = event.srcElement.parentElement.getAttribute("title")
|
||||
this.tabsService.sendEditorsServiceAMessage("set-tab-to-editor", fpath);
|
||||
// this.updateActiveTabHighlight(fpath);
|
||||
} else if ( target.classList.contains("close-button") ) {
|
||||
this.tabsService.closeTab(
|
||||
event.srcElement.parentElement.getAttribute("title")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private updateActiveTabHighlight(fpath: string): void {
|
||||
let message = new ServiceMessage();
|
||||
message.action = "highlight-active-tab";
|
||||
message.filePath = fpath;
|
||||
this.tabsService.sendMessage(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,15 +61,3 @@
|
||||
.ace_sb-h {
|
||||
width: 0.8em !important;
|
||||
}
|
||||
|
||||
|
||||
.ace_cursor {
|
||||
color: rgba(249, 148, 6, 0.64);
|
||||
animation: blinker 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,6 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
ul, li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
|
||||
/* IDs */
|
||||
|
||||
|
||||
@@ -57,13 +57,6 @@
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
.tabs-bar-underline {
|
||||
border-color: #fff;
|
||||
margin-top: -.8em;
|
||||
margin-left: -.2em;
|
||||
border-width: 0.2em;
|
||||
}
|
||||
|
||||
.hr-pane-handle,
|
||||
.vr-pane-handle {
|
||||
border: 2px dashed lightblue;
|
||||
@@ -79,28 +72,6 @@
|
||||
|
||||
|
||||
|
||||
.contextMenu {
|
||||
z-index: 999;
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
min-width: 2em;
|
||||
max-width: 8em;
|
||||
padding: 0.2em;
|
||||
top: 0em;
|
||||
right: 0em;
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
.contextMenu li:hover {
|
||||
background-color: rgba(0, 124, 0, 0.64);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.contextMenu li {
|
||||
padding: 0em 0.2em;
|
||||
}
|
||||
|
||||
|
||||
.zero-margin-padding {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
|
||||
3
src/libs/showdown.min.js
vendored
Normal file
3
src/libs/showdown.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -11,35 +11,32 @@
|
||||
import 'zone.js'; // Included with Angular CLI.
|
||||
|
||||
|
||||
// Note: Is set to 'any' b/c of desire to set 'render'
|
||||
// side if running outside of electron mode.
|
||||
declare global {
|
||||
interface Window {
|
||||
electron: {
|
||||
node: any,
|
||||
chrome: any,
|
||||
electron: any,
|
||||
node: () => Promise<string>,
|
||||
chrome: () => Promise<string>,
|
||||
electron: () => Promise<string>,
|
||||
},
|
||||
main: {
|
||||
onMenuActions: any,
|
||||
onTerminalActions: any,
|
||||
onMenuActions: (arg0: any) => Promise<string>,
|
||||
quit: any,
|
||||
toggleFullScreen: any,
|
||||
},
|
||||
fs: {
|
||||
getLspConfigData: any,
|
||||
getFileContents: any,
|
||||
openFiles: any,
|
||||
saveFile: any,
|
||||
saveFileAs: any,
|
||||
chooseFolder: any,
|
||||
closeFile: any,
|
||||
getLspConfigData: () => Promise<string>,
|
||||
getFileContents: (arg0: any) => Promise<string>,
|
||||
openFiles: (arg0) => Promise<string>,
|
||||
saveFile: (arg0: any, arg1: any) => Promise<string>,
|
||||
saveFileAs: () => Promise<string>,
|
||||
chooseFolder: () => Promise<string>,
|
||||
closeFile: (arg0: any) => Promise<string>,
|
||||
getPathForFile: any,
|
||||
onLoadFiles: any,
|
||||
onUpdateFilePath: any,
|
||||
onSavedFile: any,
|
||||
onChangedFile: any,
|
||||
onDeletedFile: any,
|
||||
onLoadFiles: (arg0: any) => Promise<string>,
|
||||
onUpdateFilePath: (arg0: any) => Promise<string>,
|
||||
onSavedFile: (arg0: any) => Promise<string>,
|
||||
onChangedFile: (arg0: any) => Promise<string>,
|
||||
onDeletedFile: (arg0: any) => Promise<string>,
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/typings.d.ts
vendored
Normal file
1
src/typings.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare var showdown: any;
|
||||
@@ -16,6 +16,50 @@
|
||||
"declaration": false,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
}
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
},
|
||||
"includes": [
|
||||
"src/typings.d.ts"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"outDir": "./build/app",
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "bundler",
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"useDefineForClassFields": false,
|
||||
"lib": [
|
||||
"ES2022",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
},
|
||||
"includes": [
|
||||
"src/typings.d.ts"
|
||||
]
|
||||
}
|
||||
|
||||
*/
|
||||
Reference in New Issue
Block a user