├── .editorconfig ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── README.md ├── build ├── entitlements.mac.plist ├── icon.icns ├── icon.ico └── icon.png ├── dev-app-update.yml ├── electron-builder.yml ├── electron.vite.config.ts ├── image.png ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── resources └── icon.png ├── src ├── main │ └── index.ts ├── preload │ ├── index.d.ts │ └── index.ts └── renderer │ ├── index.html │ └── src │ ├── App.vue │ ├── assets │ ├── global.scss │ ├── images │ │ └── cancel.svg │ └── tailwind.scss │ ├── codemirror │ ├── lang-code │ │ ├── brainfuck │ │ │ ├── brainfuck.bf │ │ │ └── index.ts │ │ ├── clojure │ │ │ ├── clojure.clj │ │ │ └── index.ts │ │ ├── coffeescript │ │ │ ├── coffeescript.coffee │ │ │ └── index.ts │ │ ├── cpp │ │ │ ├── cpp.cpp │ │ │ └── index.ts │ │ ├── css │ │ │ ├── css.css │ │ │ └── index.ts │ │ ├── dockerfile │ │ │ ├── dockerfile │ │ │ └── index.ts │ │ ├── erlang │ │ │ ├── erlang.erl │ │ │ └── index.ts │ │ ├── go │ │ │ ├── go.go │ │ │ └── index.ts │ │ ├── html │ │ │ ├── html.html │ │ │ └── index.ts │ │ ├── java │ │ │ ├── index.ts │ │ │ └── java.java │ │ ├── javascript │ │ │ ├── index.ts │ │ │ └── javascript.js │ │ ├── json │ │ │ ├── index.ts │ │ │ └── json.json │ │ ├── jsx │ │ │ ├── index.ts │ │ │ └── jsx.jsx │ │ ├── julia │ │ │ ├── index.ts │ │ │ └── julia.jl │ │ ├── lezer │ │ │ └── index.ts │ │ ├── lua │ │ │ ├── index.ts │ │ │ └── lua.lua │ │ ├── markdown │ │ │ ├── index.ts │ │ │ └── markdown.md │ │ ├── mysql │ │ │ ├── index.ts │ │ │ └── mysql.sql │ │ ├── nginx │ │ │ ├── index.ts │ │ │ └── nginx.conf │ │ ├── pascal │ │ │ ├── index.ts │ │ │ └── pascal.pas │ │ ├── perl │ │ │ ├── index.ts │ │ │ └── perl.pl │ │ ├── pgsql │ │ │ ├── index.ts │ │ │ └── pgsql.sql │ │ ├── php │ │ │ ├── index.ts │ │ │ └── php.php │ │ ├── powershell │ │ │ ├── index.ts │ │ │ └── powershell.ps1 │ │ ├── python │ │ │ ├── index.ts │ │ │ └── python.py │ │ ├── r │ │ │ ├── index.ts │ │ │ └── r.r │ │ ├── ruby │ │ │ ├── index.ts │ │ │ └── ruby.rb │ │ ├── rust │ │ │ ├── index.ts │ │ │ └── rust.rs │ │ ├── scheme │ │ │ ├── index.ts │ │ │ └── scheme.scm │ │ ├── shell │ │ │ ├── index.ts │ │ │ └── shell.sh │ │ ├── sql │ │ │ ├── index.ts │ │ │ └── sql.sql │ │ ├── stylus │ │ │ ├── index.ts │ │ │ └── stylus.styl │ │ ├── swift │ │ │ ├── index.ts │ │ │ └── swift.swift │ │ ├── tcl │ │ │ ├── index.ts │ │ │ └── tcl.tcl │ │ ├── toml │ │ │ ├── index.ts │ │ │ └── toml.toml │ │ ├── tsx │ │ │ ├── index.ts │ │ │ └── tsx.tsx │ │ ├── typescript │ │ │ ├── index.ts │ │ │ └── typescript.ts │ │ ├── vb │ │ │ ├── index.ts │ │ │ └── vb.vb │ │ ├── vbscript │ │ │ ├── index.ts │ │ │ └── vbscript.vbs │ │ ├── vue │ │ │ ├── index.ts │ │ │ └── vue.vue │ │ ├── xml │ │ │ ├── index.ts │ │ │ └── xml.xml │ │ └── yaml │ │ │ ├── index.ts │ │ │ └── yaml.yaml │ ├── language.ts │ └── theme.ts │ ├── components │ ├── Button.vue │ ├── Center.vue │ ├── CodeItem.vue │ ├── CodeList.vue │ ├── Codemirror.vue │ ├── Editor.vue │ ├── NavBar.vue │ ├── Setting.vue │ ├── ToolBar.vue │ └── Versions.vue │ ├── env.d.ts │ ├── main.ts │ ├── router │ └── index.ts │ ├── store │ └── index.ts │ ├── types.ts │ └── views │ └── Home.vue ├── tailwind.config.js ├── tsconfig.json ├── tsconfig.node.json └── tsconfig.web.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | out 4 | .gitignore 5 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | require('@rushstack/eslint-patch/modern-module-resolution') 3 | 4 | module.exports = { 5 | extends: [ 6 | 'eslint:recommended', 7 | 'plugin:vue/vue3-recommended', 8 | '@electron-toolkit', 9 | '@electron-toolkit/eslint-config-ts/eslint-recommended', 10 | '@vue/eslint-config-typescript/recommended', 11 | '@vue/eslint-config-prettier' 12 | ], 13 | rules: { 14 | 'vue/require-default-prop': 'off', 15 | 'vue/multi-word-component-names': 'off', 16 | 'max-len': 'off', 17 | '@typescript-eslint/no-explicit-any': 'off' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | out 4 | .DS_Store 5 | *.log* 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | electron_mirror=https://npmmirror.com/mirrors/electron/ 2 | electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/ 3 | shamefully-hoist=true 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore all files in the .git directory 2 | .git/* 3 | 4 | # Ignore all files in the node_modules directory 5 | node_modules/* 6 | 7 | # Ignore all files in the dist directory 8 | dist/* 9 | 10 | # Ignore all files in the build directory 11 | build/* 12 | 13 | # Ignore all files in the coverage directory 14 | coverage/* 15 | 16 | # Ignore all files in the logs directory 17 | logs/* 18 | 19 | # Ignore all files in the tmp directory 20 | tmp/* 21 | 22 | # Ignore all files in the vendor directory 23 | vendor/* 24 | 25 | # Ignore all files with the .log extension 26 | **/*.log 27 | 28 | # Ignore all files with the .zip extension 29 | **/*.zip 30 | 31 | # Ignore all files with the .gz extension 32 | **/*.gz 33 | 34 | # Ignore all files with the .tar.gz extension 35 | **/*.tar.gz 36 | 37 | # Ignore all files with the .tgz extension 38 | **/*.tgz 39 | 40 | # Ignore all files with the .idea directory 41 | .idea/** 42 | 43 | *.md 44 | *.txt -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "bracketSpacing": true, 5 | "embeddedLanguageFormatting": "auto", 6 | "htmlWhitespaceSensitivity": "css", 7 | "insertPragma": false, 8 | "jsxSingleQuote": true, 9 | "printWidth": 100, 10 | "proseWrap": "never", 11 | "quoteProps": "as-needed", 12 | "requirePragma": false, 13 | "semi": false, 14 | "singleQuote": true, 15 | "tabWidth": 4, 16 | "trailingComma": "none", 17 | "useTabs": true, 18 | "vueIndentScriptAndStyle": false, 19 | "singleAttributePerLine": false, 20 | "endOfLine": "lf" 21 | } 22 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug Main Process", 6 | "type": "node", 7 | "request": "launch", 8 | "cwd": "${workspaceRoot}", 9 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite", 10 | "windows": { 11 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd" 12 | }, 13 | "runtimeArgs": ["--sourcemap"], 14 | "env": { 15 | "REMOTE_DEBUGGING_PORT": "9222" 16 | } 17 | }, 18 | { 19 | "name": "Debug Renderer Process", 20 | "port": 9222, 21 | "request": "attach", 22 | "type": "chrome", 23 | "webRoot": "${workspaceFolder}/src/renderer", 24 | "timeout": 60000, 25 | "presentation": { 26 | "hidden": true 27 | } 28 | } 29 | ], 30 | "compounds": [ 31 | { 32 | "name": "Debug All", 33 | "configurations": ["Debug Main Process", "Debug Renderer Process"], 34 | "presentation": { 35 | "order": 1 36 | } 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[typescript]": { 3 | "editor.defaultFormatter": "esbenp.prettier-vscode" 4 | }, 5 | "[javascript]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | }, 8 | "[json]": { 9 | "editor.defaultFormatter": "esbenp.prettier-vscode" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # save-code 2 | 3 | ## Description 4 | 5 | This is a simple project to save code snippets. 6 | 7 | ## Technologies 8 | 9 | - electron 10 | - vite 11 | - vue3 12 | - tailwindcss 13 | - pinia 14 | - bytemd 15 | - antdv 16 | - vue-router 17 | - vue-codemirror 18 | - pinia-plugin-persistedstate 19 | 20 | ## Installation 21 | 22 | ```bash 23 | npm install 24 | npm run dev 25 | 26 | 打包 27 | npm run build:win 28 | npm run build:mac 29 | ``` 30 | ## Display 31 | 32 | 33 | 34 | ### 添加代码 35 | 36 | 可以选择代码的编程语言和编辑器的样式,输入代码片段的标题,在 md 编辑器中输入代码片段的内容,点击保存即可保存代码片段。 37 | 38 | ![](https://picgo-use-images.oss-cn-shanghai.aliyuncs.com/images/20240318230115.png) 39 | 40 | ### 代码中心 41 | 42 | 所有保存的代码都会显示在代码中心,可以通过标题搜索代码片段。点击代码右上角的语言标签可以直接复制。 43 | 44 | 右键某一个代码片段可以删除或者查看详情。 45 | 46 | ![](https://picgo-use-images.oss-cn-shanghai.aliyuncs.com/images/20240318230028.png) 47 | 48 | ### 配置 49 | 50 | 在此页面可以配置关闭窗口后再次从托盘弹出窗口的快捷键。 51 | 52 | ![20240319152753](https://picgo-use-images.oss-cn-shanghai.aliyuncs.com/images/20240319152753.png) -------------------------------------------------------------------------------- /build/entitlements.mac.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-jit 6 | 7 | com.apple.security.cs.allow-unsigned-executable-memory 8 | 9 | com.apple.security.cs.allow-dyld-environment-variables 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /build/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QAQDFAFD/save-code/86135db9efc77f406070dca5d4bbdf28dcb55d61/build/icon.icns -------------------------------------------------------------------------------- /build/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QAQDFAFD/save-code/86135db9efc77f406070dca5d4bbdf28dcb55d61/build/icon.ico -------------------------------------------------------------------------------- /build/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QAQDFAFD/save-code/86135db9efc77f406070dca5d4bbdf28dcb55d61/build/icon.png -------------------------------------------------------------------------------- /dev-app-update.yml: -------------------------------------------------------------------------------- 1 | provider: generic 2 | url: https://example.com/auto-updates 3 | updaterCacheDirName: save-code-updater 4 | -------------------------------------------------------------------------------- /electron-builder.yml: -------------------------------------------------------------------------------- 1 | appId: com.electron.app 2 | productName: save-code 3 | directories: 4 | buildResources: build 5 | files: 6 | - '!**/.vscode/*' 7 | - '!src/*' 8 | - '!electron.vite.config.{js,ts,mjs,cjs}' 9 | - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' 10 | - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' 11 | - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}' 12 | asarUnpack: 13 | - resources/** 14 | win: 15 | executableName: save-code 16 | nsis: 17 | artifactName: ${name}-${version}-setup.${ext} 18 | shortcutName: ${productName} 19 | uninstallDisplayName: ${productName} 20 | createDesktopShortcut: always 21 | mac: 22 | entitlementsInherit: build/entitlements.mac.plist 23 | extendInfo: 24 | - NSCameraUsageDescription: Application requests access to the device's camera. 25 | - NSMicrophoneUsageDescription: Application requests access to the device's microphone. 26 | - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. 27 | - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. 28 | notarize: false 29 | dmg: 30 | artifactName: ${name}-${version}.${ext} 31 | linux: 32 | target: 33 | - AppImage 34 | - snap 35 | - deb 36 | maintainer: electronjs.org 37 | category: Utility 38 | appImage: 39 | artifactName: ${name}-${version}.${ext} 40 | npmRebuild: false 41 | publish: 42 | provider: generic 43 | url: https://example.com/auto-updates 44 | electronDownload: 45 | mirror: https://npmmirror.com/mirrors/electron/ 46 | -------------------------------------------------------------------------------- /electron.vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | import { defineConfig, externalizeDepsPlugin } from 'electron-vite' 3 | import vue from '@vitejs/plugin-vue' 4 | 5 | export default defineConfig({ 6 | main: { 7 | plugins: [externalizeDepsPlugin()] 8 | }, 9 | preload: { 10 | plugins: [externalizeDepsPlugin()] 11 | }, 12 | renderer: { 13 | resolve: { 14 | alias: { 15 | '@renderer': resolve('src/renderer/src') 16 | } 17 | }, 18 | plugins: [vue()] 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QAQDFAFD/save-code/86135db9efc77f406070dca5d4bbdf28dcb55d61/image.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "save-code", 3 | "version": "1.0.0", 4 | "description": "An Electron application with Vue and TypeScript", 5 | "main": "./out/main/index.js", 6 | "author": "example.com", 7 | "homepage": "https://electron-vite.org", 8 | "build": { 9 | "appId": "com.lijiajun.app", 10 | "mac": { 11 | "target": [ 12 | "dmg", 13 | "zip" 14 | ] 15 | }, 16 | "win": { 17 | "target": [ 18 | "nsis", 19 | "zip" 20 | ], 21 | "icon": "resources/icon.png" 22 | }, 23 | "nsis": { 24 | "oneClick": false, 25 | "language": "2052", 26 | "perMachine": true, 27 | "allowElevation": true, 28 | "allowToChangeInstallationDirectory": true, 29 | "createDesktopShortcut": true, 30 | "createStartMenuShortcut": false 31 | } 32 | }, 33 | "scripts": { 34 | "format": "prettier --write .", 35 | "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix", 36 | "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", 37 | "typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false", 38 | "typecheck": "npm run typecheck:node && npm run typecheck:web", 39 | "start": "electron-vite preview", 40 | "dev": "electron-vite dev", 41 | "build": "electron-vite build", 42 | "postinstall": "electron-builder install-app-deps", 43 | "build:unpack": "npm run build && electron-builder --dir", 44 | "build:win": "npm run build && electron-builder --win", 45 | "build:mac": "npm run build && electron-builder --mac", 46 | "build:linux": "npm run build && electron-builder --linux" 47 | }, 48 | "dependencies": { 49 | "@bytemd/plugin-gfm": "^1.21.0", 50 | "@bytemd/vue-next": "^1.21.0", 51 | "@codemirror/commands": "^6.3.3", 52 | "@codemirror/lang-cpp": "^6.0.2", 53 | "@codemirror/lang-css": "^6.2.1", 54 | "@codemirror/lang-html": "^6.4.8", 55 | "@codemirror/lang-java": "^6.0.1", 56 | "@codemirror/lang-javascript": "^6.2.2", 57 | "@codemirror/lang-json": "^6.0.1", 58 | "@codemirror/lang-lezer": "^6.0.1", 59 | "@codemirror/lang-markdown": "^6.2.4", 60 | "@codemirror/lang-php": "^6.0.1", 61 | "@codemirror/lang-python": "^6.1.4", 62 | "@codemirror/lang-rust": "^6.0.1", 63 | "@codemirror/lang-sql": "^6.6.1", 64 | "@codemirror/lang-vue": "^0.1.3", 65 | "@codemirror/lang-xml": "^6.1.0", 66 | "@codemirror/language": "^6.10.1", 67 | "@codemirror/legacy-modes": "^6.3.3", 68 | "@codemirror/theme-one-dark": "^6.1.2", 69 | "@electron-toolkit/preload": "^3.0.0", 70 | "@electron-toolkit/utils": "^3.0.0", 71 | "ant-design-vue": "4.x", 72 | "bytemd": "^1.21.0", 73 | "clipboard": "^2.0.11", 74 | "cm6-theme-material-dark": "^0.2.0", 75 | "codemirror": "^6.0.1", 76 | "electron-updater": "^6.1.7", 77 | "pinia": "^2.1.7", 78 | "pinia-plugin-persistedstate": "^3.2.1", 79 | "sass": "^1.72.0", 80 | "thememirror": "^2.0.1", 81 | "vue-codemirror": "^6.1.1", 82 | "vue-router": "4" 83 | }, 84 | "devDependencies": { 85 | "@electron-toolkit/eslint-config": "^1.0.2", 86 | "@electron-toolkit/eslint-config-ts": "^1.0.1", 87 | "@electron-toolkit/tsconfig": "^1.0.1", 88 | "@rushstack/eslint-patch": "^1.7.1", 89 | "@types/node": "^18.19.9", 90 | "@vitejs/plugin-vue": "^5.0.3", 91 | "@vue/eslint-config-prettier": "^9.0.0", 92 | "@vue/eslint-config-typescript": "^12.0.0", 93 | "autoprefixer": "^10.4.18", 94 | "electron": "^28.2.0", 95 | "electron-vite": "^2.0.0", 96 | "eslint": "^8.56.0", 97 | "eslint-plugin-vue": "^9.20.1", 98 | "postcss": "^8.4.35", 99 | "prettier": "^3.2.4", 100 | "tailwindcss": "^3.4.1", 101 | "typescript": "^5.3.3", 102 | "vite": "^5.0.12", 103 | "vue": "^3.4.15", 104 | "vue-tsc": "^1.8.27" 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QAQDFAFD/save-code/86135db9efc77f406070dca5d4bbdf28dcb55d61/resources/icon.png -------------------------------------------------------------------------------- /src/main/index.ts: -------------------------------------------------------------------------------- 1 | import { app, shell, BrowserWindow, globalShortcut, ipcMain, Tray, Menu } from 'electron' 2 | import { join } from 'path' 3 | import { electronApp, optimizer, is } from '@electron-toolkit/utils' 4 | import icon from '../../resources/icon.png?asset' 5 | 6 | let mainWindow: BrowserWindow | null = null 7 | 8 | function createWindow(): void { 9 | // Create the browser window. 10 | mainWindow = new BrowserWindow({ 11 | width: 400, 12 | height: 700, 13 | x: 1600, 14 | y: 100, 15 | frame: false, 16 | resizable: false, 17 | autoHideMenuBar: true, 18 | alwaysOnTop: false, 19 | ...(process.platform === 'linux' ? { icon } : {}), 20 | webPreferences: { 21 | preload: join(__dirname, '../preload/index.js'), 22 | sandbox: false 23 | } 24 | }) 25 | 26 | // mainWindow.webContents.openDevTools() 27 | 28 | mainWindow.on('ready-to-show', () => { 29 | mainWindow!.show() 30 | }) 31 | 32 | mainWindow.webContents.setWindowOpenHandler(details => { 33 | shell.openExternal(details.url) 34 | return { action: 'deny' } 35 | }) 36 | 37 | // HMR for renderer base on electron-vite cli. 38 | // Load the remote URL for development or the local html file for production. 39 | if (is.dev && process.env['ELECTRON_RENDERER_URL']) { 40 | mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']) 41 | } else { 42 | mainWindow.loadFile(join(__dirname, '../renderer/index.html')) 43 | } 44 | 45 | let tray: Tray | null = null 46 | 47 | const iconPath = join(__dirname, '../../resources/icon.png') 48 | 49 | tray = new Tray(iconPath) 50 | 51 | const contextMenu = Menu.buildFromTemplate([ 52 | { 53 | label: '退出', 54 | click: () => { 55 | mainWindow!.destroy() 56 | app.quit() 57 | } 58 | } 59 | ]) 60 | 61 | tray.setToolTip('This is my application.') 62 | tray.setContextMenu(contextMenu) 63 | 64 | tray.on('click', () => { 65 | mainWindow!.show() 66 | }) 67 | } 68 | 69 | // This method will be called when Electron has finished 70 | // initialization and is ready to create browser windows. 71 | // Some APIs can only be used after this event occurs. 72 | app.whenReady().then(() => { 73 | // Set app user model id for windows 74 | electronApp.setAppUserModelId('com.electron') 75 | 76 | // Default open or close DevTools by F12 in development 77 | // and ignore CommandOrControl + R in production. 78 | // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils 79 | app.on('browser-window-created', (_, window) => { 80 | optimizer.watchWindowShortcuts(window) 81 | }) 82 | 83 | // IPC test 84 | 85 | createWindow() 86 | 87 | app.on('activate', function () { 88 | // On macOS it's common to re-create a window in the app when the 89 | // dock icon is clicked and there are no other windows open. 90 | if (BrowserWindow.getAllWindows().length === 0) createWindow() 91 | }) 92 | }) 93 | 94 | // Quit when all windows are closed, except on macOS. There, it's common 95 | // for applications and their menu bar to stay active until the user quits 96 | // explicitly with Cmd + Q. 97 | app.on('window-all-closed', () => { 98 | if (process.platform !== 'darwin') { 99 | app.quit() 100 | } 101 | }) 102 | 103 | // In this file you can include the rest of your app"s specific main process 104 | // code. You can also put them in separate files and require them here. 105 | 106 | ipcMain.handle('popUp', (_event, shortcut) => { 107 | console.log('register-shortcut', shortcut) 108 | globalShortcut.unregisterAll() 109 | const registered = globalShortcut.register(shortcut, () => { 110 | if (mainWindow && !mainWindow.isVisible()) { 111 | mainWindow.show() 112 | } else { 113 | console.log('mainWindow is null or not minimized') 114 | } 115 | }) 116 | if (!registered) { 117 | console.log('Failed to register shortcut') 118 | } 119 | }) 120 | 121 | ipcMain.handle('vanish', () => { 122 | if (mainWindow) { 123 | mainWindow.hide() 124 | } 125 | }) 126 | -------------------------------------------------------------------------------- /src/preload/index.d.ts: -------------------------------------------------------------------------------- 1 | import { ElectronAPI } from '@electron-toolkit/preload' 2 | 3 | declare global { 4 | interface Window { 5 | electron: ElectronAPI 6 | api: { 7 | shortCut: (channel: string, data: string) => void 8 | vanish: () => void 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/preload/index.ts: -------------------------------------------------------------------------------- 1 | import { contextBridge, ipcRenderer } from 'electron' 2 | import { electronAPI } from '@electron-toolkit/preload' 3 | 4 | // Custom APIs for renderer 5 | const api = { 6 | shortCut: (channel: string, data: string) => { 7 | ipcRenderer.invoke(channel, data) 8 | }, 9 | vanish: () => { 10 | ipcRenderer.invoke('vanish') 11 | } 12 | } 13 | 14 | // Use `contextBridge` APIs to expose Electron APIs to 15 | // renderer only if context isolation is enabled, otherwise 16 | // just add to the DOM global. 17 | if (process.contextIsolated) { 18 | try { 19 | contextBridge.exposeInMainWorld('electron', electronAPI) 20 | contextBridge.exposeInMainWorld('api', api) 21 | } catch (error) { 22 | console.error(error) 23 | } 24 | } else { 25 | // @ts-ignore (define in dts) 26 | window.electron = electronAPI 27 | // @ts-ignore (define in dts) 28 | window.api = api 29 | } 30 | -------------------------------------------------------------------------------- /src/renderer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Electron 7 | 8 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/renderer/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/renderer/src/assets/global.scss: -------------------------------------------------------------------------------- 1 | body { 2 | @apply bg-slate-100; 3 | overflow-x: hidden; 4 | overflow-y: auto; 5 | 6 | &::-webkit-scrollbar { 7 | width: 0 !important; 8 | } 9 | } 10 | 11 | .drag { 12 | -webkit-app-region: drag; 13 | } 14 | 15 | .no-drag, 16 | input, 17 | textarea, 18 | option { 19 | -webkit-app-region: no-drag; 20 | } 21 | 22 | // 进度条样式 23 | // .scrollbar { 24 | // -webkit-scrollbar { 25 | // width: 0.5rem; 26 | // } 27 | // -webkit-scrollbar-thumb { 28 | // background-color: rgba(0, 0, 0, 0.2); 29 | // border-radius: 0.25rem; 30 | // } 31 | // } 32 | -------------------------------------------------------------------------------- /src/renderer/src/assets/images/cancel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/renderer/src/assets/tailwind.scss: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/brainfuck/brainfuck.bf: -------------------------------------------------------------------------------- 1 | [ This program prints "Hello World!" and a newline to the screen, its 2 | length is 106 active command characters [it is not the shortest.] 3 | 4 | This loop is a "comment loop", it's a simple way of adding a comment 5 | to a BF program such that you don't have to worry about any command 6 | characters. Any ".", ",", "+", "-", "<" and ">" characters are simply 7 | ignored, the "[" and "]" characters just have to be balanced. 8 | ] 9 | +++++ +++ Set Cell #0 to 8 10 | [ 11 | >++++ Add 4 to Cell #1; this will always set Cell #1 to 4 12 | [ as the cell will be cleared by the loop 13 | >++ Add 2 to Cell #2 14 | >+++ Add 3 to Cell #3 15 | >+++ Add 3 to Cell #4 16 | >+ Add 1 to Cell #5 17 | <<<<- Decrement the loop counter in Cell #1 18 | ] Loop till Cell #1 is zero; number of iterations is 4 19 | >+ Add 1 to Cell #2 20 | >+ Add 1 to Cell #3 21 | >- Subtract 1 from Cell #4 22 | >>+ Add 1 to Cell #6 23 | [<] Move back to the first zero cell you find; this will 24 | be Cell #1 which was cleared by the previous loop 25 | <- Decrement the loop Counter in Cell #0 26 | ] Loop till Cell #0 is zero; number of iterations is 8 27 | 28 | The result of this is: 29 | Cell No : 0 1 2 3 4 5 6 30 | Contents: 0 0 72 104 88 32 8 31 | Pointer : ^ 32 | 33 | >>. Cell #2 has value 72 which is 'H' 34 | >---. Subtract 3 from Cell #3 to get 101 which is 'e' 35 | +++++++..+++. Likewise for 'llo' from Cell #3 36 | >>. Cell #5 is 32 for the space 37 | <-. Subtract 1 from Cell #4 for 87 to give a 'W' 38 | <. Cell #3 was set to 'o' from the end of 'Hello' 39 | +++.------.--------. Cell #3 for 'rl' and 'd' 40 | >>+. Add 1 to Cell #5 gives us an exclamation point 41 | >++. And finally a newline from Cell #6 -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/brainfuck/index.ts: -------------------------------------------------------------------------------- 1 | import { StreamLanguage } from '@codemirror/language' 2 | import { brainfuck } from '@codemirror/legacy-modes/mode/brainfuck' 3 | import code from './brainfuck.bf?raw' 4 | 5 | export default { 6 | language: () => StreamLanguage.define(brainfuck), 7 | code 8 | } 9 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/clojure/clojure.clj: -------------------------------------------------------------------------------- 1 | (ns game-of-life 2 | "Conway's Game of Life, based on the work of 3 | Christophe Grand (http://clj-me.cgrand.net/2011/08/19/conways-game-of-life) 4 | and Laurent Petit (https://gist.github.com/1200343).") 5 | 6 | ;;; Core game of life's algorithm functions 7 | 8 | (defn neighbors 9 | "Given a cell's coordinates `[x y]`, returns the coordinates of its 10 | neighbors." 11 | [[x y]] 12 | (for [dx [-1 0 1] 13 | dy (if (zero? dx) 14 | [-1 1] 15 | [-1 0 1])] 16 | [(+ dx x) (+ dy y)])) 17 | 18 | (defn step 19 | "Given a set of living `cells`, computes the new set of living cells." 20 | [cells] 21 | (set (for [[cell n] (frequencies (mapcat neighbors cells)) 22 | :when (or (= n 3) 23 | (and (= n 2) 24 | (cells cell)))] 25 | cell))) 26 | 27 | ;;; Utility methods for displaying game on a text terminal 28 | 29 | (defn print-grid 30 | "Prints a `grid` of `w` columns and `h` rows, on *out*, representing a 31 | step in the game." 32 | [grid w h] 33 | (doseq [x (range (inc w)) 34 | y (range (inc h))] 35 | (when (= y 0) (println)) 36 | (print (if (grid [x y]) 37 | "[X]" 38 | " . ")))) 39 | 40 | (defn print-grids 41 | "Prints a sequence of `grids` of `w` columns and `h` rows on *out*, 42 | representing several steps." 43 | [grids w h] 44 | (doseq [grid grids] 45 | (print-grid grid w h) 46 | (println))) 47 | 48 | ;;; Launches an example grid 49 | 50 | (def grid 51 | "`grid` represents the initial set of living cells" 52 | #{[2 1] [2 2] [2 3]}) 53 | 54 | (print-grids (take 3 (iterate step grid)) 5 5) -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/clojure/index.ts: -------------------------------------------------------------------------------- 1 | import { StreamLanguage } from '@codemirror/language' 2 | import { clojure } from '@codemirror/legacy-modes/mode/clojure' 3 | import code from './clojure.clj?raw' 4 | 5 | export default { 6 | language: () => StreamLanguage.define(clojure), 7 | code 8 | } 9 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/coffeescript/coffeescript.coffee: -------------------------------------------------------------------------------- 1 | # CoffeeScript mode for CodeMirror 2 | # Copyright (c) 2011 Jeff Pickhardt, released under 3 | # the MIT License. 4 | # 5 | # Modified from the Python CodeMirror mode, which also is 6 | # under the MIT License Copyright (c) 2010 Timothy Farrell. 7 | # 8 | # The following script, Underscore.coffee, is used to 9 | # demonstrate CoffeeScript mode for CodeMirror. 10 | # 11 | # To download CoffeeScript mode for CodeMirror, go to: 12 | # https://github.com/pickhardt/coffeescript-codemirror-mode 13 | 14 | # **Underscore.coffee 15 | # (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.** 16 | # Underscore is freely distributable under the terms of the 17 | # [MIT license](http://en.wikipedia.org/wiki/MIT_License). 18 | # Portions of Underscore are inspired by or borrowed from 19 | # [Prototype.js](http://prototypejs.org/api), Oliver Steele's 20 | # [Functional](http://osteele.com), and John Resig's 21 | # [Micro-Templating](http://ejohn.org). 22 | # For all details and documentation: 23 | # http://documentcloud.github.com/underscore/ 24 | 25 | 26 | # Baseline setup 27 | # -------------- 28 | 29 | # Establish the root object, `window` in the browser, or `global` on the server. 30 | root = this 31 | 32 | 33 | # Save the previous value of the `_` variable. 34 | previousUnderscore = root._ 35 | 36 | ### Multiline 37 | comment 38 | ### 39 | 40 | # Establish the object that gets thrown to break out of a loop iteration. 41 | # `StopIteration` is SOP on Mozilla. 42 | breaker = if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration 43 | 44 | 45 | #### Docco style single line comment (title) 46 | 47 | 48 | # Helper function to escape **RegExp** contents, because JS doesn't have one. 49 | escapeRegExp = (string) -> string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1') 50 | 51 | 52 | # Save bytes in the minified (but not gzipped) version: 53 | ArrayProto = Array.prototype 54 | ObjProto = Object.prototype 55 | 56 | 57 | # Create quick reference variables for speed access to core prototypes. 58 | slice = ArrayProto.slice 59 | unshift = ArrayProto.unshift 60 | toString = ObjProto.toString 61 | hasOwnProperty = ObjProto.hasOwnProperty 62 | propertyIsEnumerable = ObjProto.propertyIsEnumerable 63 | 64 | 65 | # All **ECMA5** native implementations we hope to use are declared here. 66 | nativeForEach = ArrayProto.forEach 67 | nativeMap = ArrayProto.map 68 | nativeReduce = ArrayProto.reduce 69 | nativeReduceRight = ArrayProto.reduceRight 70 | nativeFilter = ArrayProto.filter 71 | nativeEvery = ArrayProto.every 72 | nativeSome = ArrayProto.some 73 | nativeIndexOf = ArrayProto.indexOf 74 | nativeLastIndexOf = ArrayProto.lastIndexOf 75 | nativeIsArray = Array.isArray 76 | nativeKeys = Object.keys 77 | 78 | 79 | # Create a safe reference to the Underscore object for use below. 80 | _ = (obj) -> new wrapper(obj) 81 | 82 | 83 | # Export the Underscore object for **CommonJS**. 84 | if typeof(exports) != 'undefined' then exports._ = _ 85 | 86 | 87 | # Export Underscore to global scope. 88 | root._ = _ 89 | 90 | 91 | # Current version. 92 | _.VERSION = '1.1.0' 93 | 94 | 95 | # Collection Functions 96 | # -------------------- 97 | 98 | # The cornerstone, an **each** implementation. 99 | # Handles objects implementing **forEach**, arrays, and raw objects. 100 | _.each = (obj, iterator, context) -> 101 | try 102 | if nativeForEach and obj.forEach is nativeForEach 103 | obj.forEach iterator, context 104 | else if _.isNumber obj.length 105 | iterator.call context, obj[i], i, obj for i in [0...obj.length] 106 | else 107 | iterator.call context, val, key, obj for own key, val of obj 108 | catch e 109 | throw e if e isnt breaker 110 | obj 111 | 112 | 113 | # Return the results of applying the iterator to each element. Use JavaScript 114 | # 1.6's version of **map**, if possible. 115 | _.map = (obj, iterator, context) -> 116 | return obj.map(iterator, context) if nativeMap and obj.map is nativeMap 117 | results = [] 118 | _.each obj, (value, index, list) -> 119 | results.push iterator.call context, value, index, list 120 | results 121 | 122 | 123 | # **Reduce** builds up a single result from a list of values. Also known as 124 | # **inject**, or **foldl**. Uses JavaScript 1.8's version of **reduce**, if possible. 125 | _.reduce = (obj, iterator, memo, context) -> 126 | if nativeReduce and obj.reduce is nativeReduce 127 | iterator = _.bind iterator, context if context 128 | return obj.reduce iterator, memo 129 | _.each obj, (value, index, list) -> 130 | memo = iterator.call context, memo, value, index, list 131 | memo 132 | 133 | 134 | # The right-associative version of **reduce**, also known as **foldr**. Uses 135 | # JavaScript 1.8's version of **reduceRight**, if available. 136 | _.reduceRight = (obj, iterator, memo, context) -> 137 | if nativeReduceRight and obj.reduceRight is nativeReduceRight 138 | iterator = _.bind iterator, context if context 139 | return obj.reduceRight iterator, memo 140 | reversed = _.clone(_.toArray(obj)).reverse() 141 | _.reduce reversed, iterator, memo, context 142 | 143 | 144 | # Return the first value which passes a truth test. 145 | _.detect = (obj, iterator, context) -> 146 | result = null 147 | _.each obj, (value, index, list) -> 148 | if iterator.call context, value, index, list 149 | result = value 150 | _.breakLoop() 151 | result 152 | 153 | 154 | # Return all the elements that pass a truth test. Use JavaScript 1.6's 155 | # **filter**, if it exists. 156 | _.filter = (obj, iterator, context) -> 157 | return obj.filter iterator, context if nativeFilter and obj.filter is nativeFilter 158 | results = [] 159 | _.each obj, (value, index, list) -> 160 | results.push value if iterator.call context, value, index, list 161 | results 162 | 163 | 164 | # Return all the elements for which a truth test fails. 165 | _.reject = (obj, iterator, context) -> 166 | results = [] 167 | _.each obj, (value, index, list) -> 168 | results.push value if not iterator.call context, value, index, list 169 | results 170 | 171 | 172 | # Determine whether all of the elements match a truth test. Delegate to 173 | # JavaScript 1.6's **every**, if it is present. 174 | _.every = (obj, iterator, context) -> 175 | iterator ||= _.identity 176 | return obj.every iterator, context if nativeEvery and obj.every is nativeEvery 177 | result = true 178 | _.each obj, (value, index, list) -> 179 | _.breakLoop() unless (result = result and iterator.call(context, value, index, list)) 180 | result 181 | 182 | 183 | # Determine if at least one element in the object matches a truth test. Use 184 | # JavaScript 1.6's **some**, if it exists. 185 | _.some = (obj, iterator, context) -> 186 | iterator ||= _.identity 187 | return obj.some iterator, context if nativeSome and obj.some is nativeSome 188 | result = false 189 | _.each obj, (value, index, list) -> 190 | _.breakLoop() if (result = iterator.call(context, value, index, list)) 191 | result 192 | 193 | 194 | # Determine if a given value is included in the array or object, 195 | # based on `===`. 196 | _.include = (obj, target) -> 197 | return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf 198 | return true for own key, val of obj when val is target 199 | false 200 | 201 | 202 | # Invoke a method with arguments on every item in a collection. 203 | _.invoke = (obj, method) -> 204 | args = _.rest arguments, 2 205 | (if method then val[method] else val).apply(val, args) for val in obj 206 | 207 | 208 | # Convenience version of a common use case of **map**: fetching a property. 209 | _.pluck = (obj, key) -> 210 | _.map(obj, (val) -> val[key]) 211 | 212 | 213 | # Return the maximum item or (item-based computation). 214 | _.max = (obj, iterator, context) -> 215 | return Math.max.apply(Math, obj) if not iterator and _.isArray(obj) 216 | result = computed: -Infinity 217 | _.each obj, (value, index, list) -> 218 | computed = if iterator then iterator.call(context, value, index, list) else value 219 | computed >= result.computed and (result = {value: value, computed: computed}) 220 | result.value 221 | 222 | 223 | # Return the minimum element (or element-based computation). 224 | _.min = (obj, iterator, context) -> 225 | return Math.min.apply(Math, obj) if not iterator and _.isArray(obj) 226 | result = computed: Infinity 227 | _.each obj, (value, index, list) -> 228 | computed = if iterator then iterator.call(context, value, index, list) else value 229 | computed < result.computed and (result = {value: value, computed: computed}) 230 | result.value 231 | 232 | 233 | # Sort the object's values by a criterion produced by an iterator. 234 | _.sortBy = (obj, iterator, context) -> 235 | _.pluck(((_.map obj, (value, index, list) -> 236 | {value: value, criteria: iterator.call(context, value, index, list)} 237 | ).sort((left, right) -> 238 | a = left.criteria; b = right.criteria 239 | if a < b then -1 else if a > b then 1 else 0 240 | )), 'value') 241 | 242 | 243 | # Use a comparator function to figure out at what index an object should 244 | # be inserted so as to maintain order. Uses binary search. 245 | _.sortedIndex = (array, obj, iterator) -> 246 | iterator ||= _.identity 247 | low = 0 248 | high = array.length 249 | while low < high 250 | mid = (low + high) >> 1 251 | if iterator(array[mid]) < iterator(obj) then low = mid + 1 else high = mid 252 | low 253 | 254 | 255 | # Convert anything iterable into a real, live array. 256 | _.toArray = (iterable) -> 257 | return [] if (!iterable) 258 | return iterable.toArray() if (iterable.toArray) 259 | return iterable if (_.isArray(iterable)) 260 | return slice.call(iterable) if (_.isArguments(iterable)) 261 | _.values(iterable) 262 | 263 | 264 | # Return the number of elements in an object. 265 | _.size = (obj) -> _.toArray(obj).length 266 | 267 | 268 | # Array Functions 269 | # --------------- 270 | 271 | # Get the first element of an array. Passing `n` will return the first N 272 | # values in the array. Aliased as **head**. The `guard` check allows it to work 273 | # with **map**. 274 | _.first = (array, n, guard) -> 275 | if n and not guard then slice.call(array, 0, n) else array[0] 276 | 277 | 278 | # Returns everything but the first entry of the array. Aliased as **tail**. 279 | # Especially useful on the arguments object. Passing an `index` will return 280 | # the rest of the values in the array from that index onward. The `guard` 281 | # check allows it to work with **map**. 282 | _.rest = (array, index, guard) -> 283 | slice.call(array, if _.isUndefined(index) or guard then 1 else index) 284 | 285 | 286 | # Get the last element of an array. 287 | _.last = (array) -> array[array.length - 1] 288 | 289 | 290 | # Trim out all falsy values from an array. 291 | _.compact = (array) -> item for item in array when item 292 | 293 | 294 | # Return a completely flattened version of an array. 295 | _.flatten = (array) -> 296 | _.reduce array, (memo, value) -> 297 | return memo.concat(_.flatten(value)) if _.isArray value 298 | memo.push value 299 | memo 300 | , [] 301 | 302 | 303 | # Return a version of the array that does not contain the specified value(s). 304 | _.without = (array) -> 305 | values = _.rest arguments 306 | val for val in _.toArray(array) when not _.include values, val 307 | 308 | 309 | # Produce a duplicate-free version of the array. If the array has already 310 | # been sorted, you have the option of using a faster algorithm. 311 | _.uniq = (array, isSorted) -> 312 | memo = [] 313 | for el, i in _.toArray array 314 | memo.push el if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el)) 315 | memo 316 | 317 | 318 | # Produce an array that contains every item shared between all the 319 | # passed-in arrays. 320 | _.intersect = (array) -> 321 | rest = _.rest arguments 322 | _.select _.uniq(array), (item) -> 323 | _.all rest, (other) -> 324 | _.indexOf(other, item) >= 0 325 | 326 | 327 | # Zip together multiple lists into a single array -- elements that share 328 | # an index go together. 329 | _.zip = -> 330 | length = _.max _.pluck arguments, 'length' 331 | results = new Array length 332 | for i in [0...length] 333 | results[i] = _.pluck arguments, String i 334 | results 335 | 336 | 337 | # If the browser doesn't supply us with **indexOf** (I'm looking at you, MSIE), 338 | # we need this function. Return the position of the first occurrence of an 339 | # item in an array, or -1 if the item is not included in the array. 340 | _.indexOf = (array, item) -> 341 | return array.indexOf item if nativeIndexOf and array.indexOf is nativeIndexOf 342 | i = 0; l = array.length 343 | while l - i 344 | if array[i] is item then return i else i++ 345 | -1 346 | 347 | 348 | # Provide JavaScript 1.6's **lastIndexOf**, delegating to the native function, 349 | # if possible. 350 | _.lastIndexOf = (array, item) -> 351 | return array.lastIndexOf(item) if nativeLastIndexOf and array.lastIndexOf is nativeLastIndexOf 352 | i = array.length 353 | while i 354 | if array[i] is item then return i else i-- 355 | -1 356 | 357 | 358 | # Generate an integer Array containing an arithmetic progression. A port of 359 | # [the native Python **range** function](http://docs.python.org/library/functions.html#range). 360 | _.range = (start, stop, step) -> 361 | a = arguments 362 | solo = a.length <= 1 363 | i = start = if solo then 0 else a[0] 364 | stop = if solo then a[0] else a[1] 365 | step = a[2] or 1 366 | len = Math.ceil((stop - start) / step) 367 | return [] if len <= 0 368 | range = new Array len 369 | idx = 0 370 | loop 371 | return range if (if step > 0 then i - stop else stop - i) >= 0 372 | range[idx] = i 373 | idx++ 374 | i+= step 375 | 376 | 377 | # Function Functions 378 | # ------------------ 379 | 380 | # Create a function bound to a given object (assigning `this`, and arguments, 381 | # optionally). Binding with arguments is also known as **curry**. 382 | _.bind = (func, obj) -> 383 | args = _.rest arguments, 2 384 | -> func.apply obj or root, args.concat arguments 385 | 386 | 387 | # Bind all of an object's methods to that object. Useful for ensuring that 388 | # all callbacks defined on an object belong to it. 389 | _.bindAll = (obj) -> 390 | funcs = if arguments.length > 1 then _.rest(arguments) else _.functions(obj) 391 | _.each funcs, (f) -> obj[f] = _.bind obj[f], obj 392 | obj 393 | 394 | 395 | # Delays a function for the given number of milliseconds, and then calls 396 | # it with the arguments supplied. 397 | _.delay = (func, wait) -> 398 | args = _.rest arguments, 2 399 | setTimeout((-> func.apply(func, args)), wait) 400 | 401 | 402 | # Memoize an expensive function by storing its results. 403 | _.memoize = (func, hasher) -> 404 | memo = {} 405 | hasher or= _.identity 406 | -> 407 | key = hasher.apply this, arguments 408 | return memo[key] if key of memo 409 | memo[key] = func.apply this, arguments 410 | 411 | 412 | # Defers a function, scheduling it to run after the current call stack has 413 | # cleared. 414 | _.defer = (func) -> 415 | _.delay.apply _, [func, 1].concat _.rest arguments 416 | 417 | 418 | # Returns the first function passed as an argument to the second, 419 | # allowing you to adjust arguments, run code before and after, and 420 | # conditionally execute the original function. 421 | _.wrap = (func, wrapper) -> 422 | -> wrapper.apply wrapper, [func].concat arguments 423 | 424 | 425 | # Returns a function that is the composition of a list of functions, each 426 | # consuming the return value of the function that follows. 427 | _.compose = -> 428 | funcs = arguments 429 | -> 430 | args = arguments 431 | for i in [funcs.length - 1..0] by -1 432 | args = [funcs[i].apply(this, args)] 433 | args[0] 434 | 435 | 436 | # Object Functions 437 | # ---------------- 438 | 439 | # Retrieve the names of an object's properties. 440 | _.keys = nativeKeys or (obj) -> 441 | return _.range 0, obj.length if _.isArray(obj) 442 | key for key, val of obj 443 | 444 | 445 | # Retrieve the values of an object's properties. 446 | _.values = (obj) -> 447 | _.map obj, _.identity 448 | 449 | 450 | # Return a sorted list of the function names available in Underscore. 451 | _.functions = (obj) -> 452 | _.filter(_.keys(obj), (key) -> _.isFunction(obj[key])).sort() 453 | 454 | 455 | # Extend a given object with all of the properties in a source object. 456 | _.extend = (obj) -> 457 | for source in _.rest(arguments) 458 | obj[key] = val for key, val of source 459 | obj 460 | 461 | 462 | # Create a (shallow-cloned) duplicate of an object. 463 | _.clone = (obj) -> 464 | return obj.slice 0 if _.isArray obj 465 | _.extend {}, obj 466 | 467 | 468 | # Invokes interceptor with the obj, and then returns obj. 469 | # The primary purpose of this method is to "tap into" a method chain, 470 | # in order to perform operations on intermediate results within 471 | the chain. 472 | _.tap = (obj, interceptor) -> 473 | interceptor obj 474 | obj 475 | 476 | 477 | # Perform a deep comparison to check if two objects are equal. 478 | _.isEqual = (a, b) -> 479 | # Check object identity. 480 | return true if a is b 481 | # Different types? 482 | atype = typeof(a); btype = typeof(b) 483 | return false if atype isnt btype 484 | # Basic equality test (watch out for coercions). 485 | return true if `a == b` 486 | # One is falsy and the other truthy. 487 | return false if (!a and b) or (a and !b) 488 | # One of them implements an `isEqual()`? 489 | return a.isEqual(b) if a.isEqual 490 | # Check dates' integer values. 491 | return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b) 492 | # Both are NaN? 493 | return false if _.isNaN(a) and _.isNaN(b) 494 | # Compare regular expressions. 495 | if _.isRegExp(a) and _.isRegExp(b) 496 | return a.source is b.source and 497 | a.global is b.global and 498 | a.ignoreCase is b.ignoreCase and 499 | a.multiline is b.multiline 500 | # If a is not an object by this point, we can't handle it. 501 | return false if atype isnt 'object' 502 | # Check for different array lengths before comparing contents. 503 | return false if a.length and (a.length isnt b.length) 504 | # Nothing else worked, deep compare the contents. 505 | aKeys = _.keys(a); bKeys = _.keys(b) 506 | # Different object sizes? 507 | return false if aKeys.length isnt bKeys.length 508 | # Recursive comparison of contents. 509 | return false for key, val of a when !(key of b) or !_.isEqual(val, b[key]) 510 | true 511 | 512 | 513 | # Is a given array or object empty? 514 | _.isEmpty = (obj) -> 515 | return obj.length is 0 if _.isArray(obj) or _.isString(obj) 516 | return false for own key of obj 517 | true 518 | 519 | 520 | # Is a given value a DOM element? 521 | _.isElement = (obj) -> obj and obj.nodeType is 1 522 | 523 | 524 | # Is a given value an array? 525 | _.isArray = nativeIsArray or (obj) -> !!(obj and obj.concat and obj.unshift and not obj.callee) 526 | 527 | 528 | # Is a given variable an arguments object? 529 | _.isArguments = (obj) -> obj and obj.callee 530 | 531 | 532 | # Is the given value a function? 533 | _.isFunction = (obj) -> !!(obj and obj.constructor and obj.call and obj.apply) 534 | 535 | 536 | # Is the given value a string? 537 | _.isString = (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr)) 538 | 539 | 540 | # Is a given value a number? 541 | _.isNumber = (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]' 542 | 543 | 544 | # Is a given value a boolean? 545 | _.isBoolean = (obj) -> obj is true or obj is false 546 | 547 | 548 | # Is a given value a Date? 549 | _.isDate = (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear) 550 | 551 | 552 | # Is the given value a regular expression? 553 | _.isRegExp = (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false)) 554 | 555 | 556 | # Is the given value NaN -- this one is interesting. `NaN != NaN`, and 557 | # `isNaN(undefined) == true`, so we make sure it's a number first. 558 | _.isNaN = (obj) -> _.isNumber(obj) and window.isNaN(obj) 559 | 560 | 561 | # Is a given value equal to null? 562 | _.isNull = (obj) -> obj is null 563 | 564 | 565 | # Is a given variable undefined? 566 | _.isUndefined = (obj) -> typeof obj is 'undefined' 567 | 568 | 569 | # Utility Functions 570 | # ----------------- 571 | 572 | # Run Underscore.js in noConflict mode, returning the `_` variable to its 573 | # previous owner. Returns a reference to the Underscore object. 574 | _.noConflict = -> 575 | root._ = previousUnderscore 576 | this 577 | 578 | 579 | # Keep the identity function around for default iterators. 580 | _.identity = (value) -> value 581 | 582 | 583 | # Run a function `n` times. 584 | _.times = (n, iterator, context) -> 585 | iterator.call context, i for i in [0...n] 586 | 587 | 588 | # Break out of the middle of an iteration. 589 | _.breakLoop = -> throw breaker 590 | 591 | 592 | # Add your own custom functions to the Underscore object, ensuring that 593 | # they're correctly added to the OOP wrapper as well. 594 | _.mixin = (obj) -> 595 | for name in _.functions(obj) 596 | addToWrapper name, _[name] = obj[name] 597 | 598 | 599 | # Generate a unique integer id (unique within the entire client session). 600 | # Useful for temporary DOM ids. 601 | idCounter = 0 602 | _.uniqueId = (prefix) -> 603 | (prefix or '') + idCounter++ 604 | 605 | 606 | # By default, Underscore uses **ERB**-style template delimiters, change the 607 | # following template settings to use alternative delimiters. 608 | _.templateSettings = { 609 | start: '<%' 610 | end: '%>' 611 | interpolate: /<%=(.+?)%>/g 612 | } 613 | 614 | 615 | # JavaScript templating a-la **ERB**, pilfered from John Resig's 616 | # *Secrets of the JavaScript Ninja*, page 83. 617 | # Single-quote fix from Rick Strahl. 618 | # With alterations for arbitrary delimiters, and to preserve whitespace. 619 | _.template = (str, data) -> 620 | c = _.templateSettings 621 | endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g") 622 | fn = new Function 'obj', 623 | 'var p=[],print=function(){p.push.apply(p,arguments);};' + 624 | 'with(obj||{}){p.push(\'' + 625 | str.replace(/\r/g, '\\r') 626 | .replace(/\n/g, '\\n') 627 | .replace(/\t/g, '\\t') 628 | .replace(endMatch,"���") 629 | .split("'").join("\\'") 630 | .split("���").join("'") 631 | .replace(c.interpolate, "',$1,'") 632 | .split(c.start).join("');") 633 | .split(c.end).join("p.push('") + 634 | "');}return p.join('');" 635 | if data then fn(data) else fn 636 | 637 | 638 | # Aliases 639 | # ------- 640 | 641 | _.forEach = _.each 642 | _.foldl = _.inject = _.reduce 643 | _.foldr = _.reduceRight 644 | _.select = _.filter 645 | _.all = _.every 646 | _.any = _.some 647 | _.contains = _.include 648 | _.head = _.first 649 | _.tail = _.rest 650 | _.methods = _.functions 651 | 652 | 653 | # Setup the OOP Wrapper 654 | # --------------------- 655 | 656 | # If Underscore is called as a function, it returns a wrapped object that 657 | # can be used OO-style. This wrapper holds altered versions of all the 658 | # underscore functions. Wrapped objects may be chained. 659 | wrapper = (obj) -> 660 | this._wrapped = obj 661 | this 662 | 663 | 664 | # Helper function to continue chaining intermediate results. 665 | result = (obj, chain) -> 666 | if chain then _(obj).chain() else obj 667 | 668 | 669 | # A method to easily add functions to the OOP wrapper. 670 | addToWrapper = (name, func) -> 671 | wrapper.prototype[name] = -> 672 | args = _.toArray arguments 673 | unshift.call args, this._wrapped 674 | result func.apply(_, args), this._chain 675 | 676 | 677 | # Add all ofthe Underscore functions to the wrapper object. 678 | _.mixin _ 679 | 680 | 681 | # Add all mutator Array functions to the wrapper. 682 | _.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) -> 683 | method = Array.prototype[name] 684 | wrapper.prototype[name] = -> 685 | method.apply(this._wrapped, arguments) 686 | result(this._wrapped, this._chain) 687 | 688 | 689 | # Add all accessor Array functions to the wrapper. 690 | _.each ['concat', 'join', 'slice'], (name) -> 691 | method = Array.prototype[name] 692 | wrapper.prototype[name] = -> 693 | result(method.apply(this._wrapped, arguments), this._chain) 694 | 695 | 696 | # Start chaining a wrapped Underscore object. 697 | wrapper::chain = -> 698 | this._chain = true 699 | this 700 | 701 | 702 | # Extracts the result from a wrapped and chained object. 703 | wrapper::value = -> this._wrapped 704 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/coffeescript/index.ts: -------------------------------------------------------------------------------- 1 | import { StreamLanguage } from '@codemirror/language' 2 | import { coffeeScript } from '@codemirror/legacy-modes/mode/coffeescript' 3 | import code from './coffeescript.coffee?raw' 4 | 5 | export default { 6 | language: () => StreamLanguage.define(coffeeScript), 7 | code 8 | } 9 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/cpp/cpp.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Direct3DBase.h" 3 | 4 | using namespace Microsoft::WRL; 5 | using namespace Windows::UI::Core; 6 | using namespace Windows::Foundation; 7 | 8 | // Constructor. 9 | Direct3DBase::Direct3DBase() 10 | { 11 | } 12 | 13 | // Initialize the Direct3D resources required to run. 14 | void Direct3DBase::Initialize(CoreWindow^ window) 15 | { 16 | m_window = window; 17 | 18 | CreateDeviceResources(); 19 | CreateWindowSizeDependentResources(); 20 | } 21 | 22 | // These are the resources that depend on the device. 23 | void Direct3DBase::CreateDeviceResources() 24 | { 25 | // This flag adds support for surfaces with a different color channel ordering than the API default. 26 | // It is recommended usage, and is required for compatibility with Direct2D. 27 | UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; 28 | 29 | #if defined(_DEBUG) 30 | // If the project is in a debug build, enable debugging via SDK Layers with this flag. 31 | creationFlags |= D3D11_CREATE_DEVICE_DEBUG; 32 | #endif 33 | 34 | // This array defines the set of DirectX hardware feature levels this app will support. 35 | // Note the ordering should be preserved. 36 | // Don't forget to declare your application's minimum required feature level in its 37 | // description. All applications are assumed to support 9.1 unless otherwise stated. 38 | D3D_FEATURE_LEVEL featureLevels[] = 39 | { 40 | D3D_FEATURE_LEVEL_11_1, 41 | D3D_FEATURE_LEVEL_11_0, 42 | D3D_FEATURE_LEVEL_10_1, 43 | D3D_FEATURE_LEVEL_10_0, 44 | D3D_FEATURE_LEVEL_9_3, 45 | D3D_FEATURE_LEVEL_9_2, 46 | D3D_FEATURE_LEVEL_9_1 47 | }; 48 | 49 | // Create the DX11 API device object, and get a corresponding context. 50 | ComPtr device; 51 | ComPtr context; 52 | DX::ThrowIfFailed( 53 | D3D11CreateDevice( 54 | nullptr, // specify null to use the default adapter 55 | D3D_DRIVER_TYPE_HARDWARE, 56 | nullptr, // leave as nullptr unless software device 57 | creationFlags, // optionally set debug and Direct2D compatibility flags 58 | featureLevels, // list of feature levels this app can support 59 | ARRAYSIZE(featureLevels), // number of entries in above list 60 | D3D11_SDK_VERSION, // always set this to D3D11_SDK_VERSION 61 | &device, // returns the Direct3D device created 62 | &m_featureLevel, // returns feature level of device created 63 | &context // returns the device immediate context 64 | ) 65 | ); 66 | 67 | // Get the DirectX11.1 device by QI off the DirectX11 one. 68 | DX::ThrowIfFailed( 69 | device.As(&m_d3dDevice) 70 | ); 71 | 72 | // And get the corresponding device context in the same way. 73 | DX::ThrowIfFailed( 74 | context.As(&m_d3dContext) 75 | ); 76 | } 77 | 78 | // Allocate all memory resources that change on a window SizeChanged event. 79 | void Direct3DBase::CreateWindowSizeDependentResources() 80 | { 81 | // Store the window bounds so the next time we get a SizeChanged event we can 82 | // avoid rebuilding everything if the size is identical. 83 | m_windowBounds = m_window->Bounds; 84 | 85 | // If the swap chain already exists, resize it. 86 | if(m_swapChain != nullptr) 87 | { 88 | DX::ThrowIfFailed( 89 | m_swapChain->ResizeBuffers(2, 0, 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0) 90 | ); 91 | } 92 | // Otherwise, create a new one. 93 | else 94 | { 95 | // Create a descriptor for the swap chain. 96 | DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; 97 | swapChainDesc.Width = 0; // use automatic sizing 98 | swapChainDesc.Height = 0; 99 | swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format 100 | swapChainDesc.Stereo = false; 101 | swapChainDesc.SampleDesc.Count = 1; // don't use multi-sampling 102 | swapChainDesc.SampleDesc.Quality = 0; 103 | swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 104 | swapChainDesc.BufferCount = 2; // use two buffers to enable flip effect 105 | swapChainDesc.Scaling = DXGI_SCALING_NONE; 106 | swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // we recommend using this swap effect for all applications 107 | swapChainDesc.Flags = 0; 108 | 109 | // Once the desired swap chain description is configured, it must be created on the same adapter as our D3D Device 110 | 111 | // First, retrieve the underlying DXGI Device from the D3D Device 112 | ComPtr dxgiDevice; 113 | DX::ThrowIfFailed( 114 | m_d3dDevice.As(&dxgiDevice) 115 | ); 116 | 117 | // Identify the physical adapter (GPU or card) this device is running on. 118 | ComPtr dxgiAdapter; 119 | DX::ThrowIfFailed( 120 | dxgiDevice->GetAdapter(&dxgiAdapter) 121 | ); 122 | 123 | // And obtain the factory object that created it. 124 | ComPtr dxgiFactory; 125 | DX::ThrowIfFailed( 126 | dxgiAdapter->GetParent( 127 | __uuidof(IDXGIFactory2), 128 | &dxgiFactory 129 | ) 130 | ); 131 | 132 | Windows::UI::Core::CoreWindow^ p = m_window.Get(); 133 | 134 | // Create a swap chain for this window from the DXGI factory. 135 | DX::ThrowIfFailed( 136 | dxgiFactory->CreateSwapChainForCoreWindow( 137 | m_d3dDevice.Get(), 138 | reinterpret_cast(p), 139 | &swapChainDesc, 140 | nullptr, // allow on all displays 141 | &m_swapChain 142 | ) 143 | ); 144 | 145 | // Ensure that DXGI does not queue more than one frame at a time. This both reduces 146 | // latency and ensures that the application will only render after each VSync, minimizing 147 | // power consumption. 148 | DX::ThrowIfFailed( 149 | dxgiDevice->SetMaximumFrameLatency(1) 150 | ); 151 | } 152 | 153 | // Obtain the backbuffer for this window which will be the final 3D rendertarget. 154 | ComPtr backBuffer; 155 | DX::ThrowIfFailed( 156 | m_swapChain->GetBuffer( 157 | 0, 158 | __uuidof(ID3D11Texture2D), 159 | &backBuffer 160 | ) 161 | ); 162 | 163 | // Create a view interface on the rendertarget to use on bind. 164 | DX::ThrowIfFailed( 165 | m_d3dDevice->CreateRenderTargetView( 166 | backBuffer.Get(), 167 | nullptr, 168 | &m_renderTargetView 169 | ) 170 | ); 171 | 172 | // Cache the rendertarget dimensions in our helper class for convenient use. 173 | D3D11_TEXTURE2D_DESC backBufferDesc; 174 | backBuffer->GetDesc(&backBufferDesc); 175 | m_renderTargetSize.Width = static_cast(backBufferDesc.Width); 176 | m_renderTargetSize.Height = static_cast(backBufferDesc.Height); 177 | 178 | // Create a descriptor for the depth/stencil buffer. 179 | CD3D11_TEXTURE2D_DESC depthStencilDesc( 180 | DXGI_FORMAT_D24_UNORM_S8_UINT, 181 | backBufferDesc.Width, 182 | backBufferDesc.Height, 183 | 1, 184 | 1, 185 | D3D11_BIND_DEPTH_STENCIL); 186 | 187 | // Allocate a 2-D surface as the depth/stencil buffer. 188 | ComPtr depthStencil; 189 | DX::ThrowIfFailed( 190 | m_d3dDevice->CreateTexture2D( 191 | &depthStencilDesc, 192 | nullptr, 193 | &depthStencil 194 | ) 195 | ); 196 | 197 | // Create a DepthStencil view on this surface to use on bind. 198 | DX::ThrowIfFailed( 199 | m_d3dDevice->CreateDepthStencilView( 200 | depthStencil.Get(), 201 | &CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D), 202 | &m_depthStencilView 203 | ) 204 | ); 205 | 206 | // Create a viewport descriptor of the full window size. 207 | CD3D11_VIEWPORT viewPort( 208 | 0.0f, 209 | 0.0f, 210 | static_cast(backBufferDesc.Width), 211 | static_cast(backBufferDesc.Height) 212 | ); 213 | 214 | // Set the current viewport using the descriptor. 215 | m_d3dContext->RSSetViewports(1, &viewPort); 216 | } 217 | 218 | void Direct3DBase::UpdateForWindowSizeChange() 219 | { 220 | if (m_window->Bounds.Width != m_windowBounds.Width || 221 | m_window->Bounds.Height != m_windowBounds.Height) 222 | { 223 | m_renderTargetView = nullptr; 224 | m_depthStencilView = nullptr; 225 | CreateWindowSizeDependentResources(); 226 | } 227 | } 228 | 229 | void Direct3DBase::Present() 230 | { 231 | // The first argument instructs DXGI to block until VSync, putting the application 232 | // to sleep until the next VSync. This ensures we don't waste any cycles rendering 233 | // frames that will never be displayed to the screen. 234 | HRESULT hr = m_swapChain->Present(1, 0); 235 | 236 | // If the device was removed either by a disconnect or a driver upgrade, we 237 | // must completely reinitialize the renderer. 238 | if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) 239 | { 240 | Initialize(m_window.Get()); 241 | } 242 | else 243 | { 244 | DX::ThrowIfFailed(hr); 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/cpp/index.ts: -------------------------------------------------------------------------------- 1 | import { cpp } from '@codemirror/lang-cpp' 2 | import code from './cpp.cpp?raw' 3 | 4 | export default { 5 | language: cpp, 6 | code 7 | } 8 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/css/css.css: -------------------------------------------------------------------------------- 1 | /* Some example CSS */ 2 | 3 | @import url('something.css'); 4 | 5 | body { 6 | margin: 0; 7 | padding: 3em 6em; 8 | font-family: tahoma, arial, sans-serif; 9 | color: #000; 10 | } 11 | 12 | #navigation a { 13 | font-weight: bold; 14 | text-decoration: none !important; 15 | } 16 | 17 | h1 { 18 | font-size: 2.5em; 19 | } 20 | 21 | h2 { 22 | font-size: 1.7em; 23 | } 24 | 25 | h1:before, 26 | h2:before { 27 | content: '::'; 28 | } 29 | 30 | code { 31 | font-family: courier, monospace; 32 | font-size: 80%; 33 | color: #418a8a; 34 | } 35 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/css/index.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@codemirror/lang-css' 2 | import code from './css.css?raw' 3 | 4 | export default { 5 | language: css, 6 | code 7 | } 8 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/dockerfile/dockerfile: -------------------------------------------------------------------------------- 1 | # Install Ghost blogging platform and run development environment 2 | # 3 | # VERSION 1.0.0 4 | 5 | FROM ubuntu:12.10 6 | MAINTAINER Amer Grgic "amer@livebyt.es" 7 | WORKDIR /data/ghost 8 | 9 | # Install dependencies for nginx installation 10 | RUN apt-get update 11 | RUN apt-get install -y python g++ make software-properties-common --force-yes 12 | RUN add-apt-repository ppa:chris-lea/node.js 13 | RUN apt-get update 14 | # Install unzip 15 | RUN apt-get install -y unzip 16 | # Install curl 17 | RUN apt-get install -y curl 18 | # Install nodejs & npm 19 | RUN apt-get install -y rlwrap 20 | RUN apt-get install -y nodejs 21 | # Download Ghost v0.4.1 22 | RUN curl -L https://ghost.org/zip/ghost-latest.zip -o /tmp/ghost.zip 23 | # Unzip Ghost zip to /data/ghost 24 | RUN unzip -uo /tmp/ghost.zip -d /data/ghost 25 | # Add custom config js to /data/ghost 26 | ADD ./config.example.js /data/ghost/config.js 27 | # Install Ghost with NPM 28 | RUN cd /data/ghost/ && npm install --production 29 | # Expose port 2368 30 | EXPOSE 2368 31 | # Run Ghost 32 | CMD ["npm","start"] 33 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/dockerfile/index.ts: -------------------------------------------------------------------------------- 1 | import { StreamLanguage } from '@codemirror/language' 2 | import { dockerFile } from '@codemirror/legacy-modes/mode/dockerfile' 3 | import code from './dockerfile?raw' 4 | 5 | export default { 6 | language: () => StreamLanguage.define(dockerFile), 7 | code 8 | } 9 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/erlang/erlang.erl: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang; erlang-indent-level: 2 -*- 2 | %%% Created : 7 May 2012 by mats cronqvist 3 | 4 | %% @doc 5 | %% Demonstrates how to print a record. 6 | %% @end 7 | 8 | -module('ex'). 9 | -author('mats cronqvist'). 10 | -export([demo/0, 11 | rec_info/1]). 12 | 13 | -record(demo,{a="One",b="Two",c="Three",d="Four"}). 14 | 15 | rec_info(demo) -> record_info(fields,demo). 16 | 17 | demo() -> expand_recs(?MODULE,#demo{a="A",b="BB"}). 18 | 19 | expand_recs(M,List) when is_list(List) -> 20 | [expand_recs(M,L)||L<-List]; 21 | expand_recs(M,Tup) when is_tuple(Tup) -> 22 | case tuple_size(Tup) of 23 | L when L < 1 -> Tup; 24 | L -> 25 | try 26 | Fields = M:rec_info(element(1,Tup)), 27 | L = length(Fields)+1, 28 | lists:zip(Fields,expand_recs(M,tl(tuple_to_list(Tup)))) 29 | catch 30 | _:_ -> list_to_tuple(expand_recs(M,tuple_to_list(Tup))) 31 | end 32 | end; 33 | expand_recs(_,Term) -> 34 | Term. 35 | 36 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/erlang/index.ts: -------------------------------------------------------------------------------- 1 | import { StreamLanguage } from '@codemirror/language' 2 | import { erlang } from '@codemirror/legacy-modes/mode/erlang' 3 | import code from './erlang.erl?raw' 4 | 5 | export default { 6 | language: () => StreamLanguage.define(erlang), 7 | code 8 | } 9 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/go/go.go: -------------------------------------------------------------------------------- 1 | package main 2 | import ( 3 | "fmt" 4 | "errors" 5 | "strings" 6 | ) 7 | type Value struct { 8 | Name string 9 | MilesAway int 10 | } 11 | type Node struct { 12 | Value // Embedded struct 13 | next, prev *Node 14 | } 15 | type List struct { 16 | head, tail *Node 17 | } 18 | func (l *List) First() *Node { 19 | return l.head 20 | } 21 | func (n *Node) Next() *Node { 22 | return n.next 23 | } 24 | func (n *Node) Prev() *Node { 25 | return n.prev 26 | } 27 | // Create new node with value 28 | func (l *List) Push(v Value) *List { 29 | n := &Node{Value: v} 30 | if l.head == nil { 31 | l.head = n // First node 32 | } else { 33 | l.tail.next = n // Add after prev last node 34 | n.prev = l.tail // Link back to prev last node 35 | } 36 | l.tail = n // reset tail to newly added node 37 | return l 38 | } 39 | func (l *List) Find(name string) *Node { 40 | found := false 41 | var ret *Node = nil 42 | for n := l.First(); n != nil && !found; n = n.Next() { 43 | if n.Value.Name == name { 44 | found = true 45 | ret = n 46 | } 47 | } 48 | return ret 49 | } 50 | func (l *List) Delete(name string) bool { 51 | success := false 52 | node2del := l.Find(name) 53 | if node2del != nil { 54 | fmt.Println("Delete - FOUND: ", name) 55 | prev_node := node2del.prev 56 | next_node := node2del.next 57 | // Remove this node 58 | prev_node.next = node2del.next 59 | next_node.prev = node2del.prev 60 | success = true 61 | } 62 | return success 63 | } 64 | var errEmpty = errors.New("ERROR - List is empty") 65 | // Pop last item from list 66 | func (l *List) Pop() (v Value, err error) { 67 | if l.tail == nil { 68 | err = errEmpty 69 | } else { 70 | v = l.tail.Value 71 | l.tail = l.tail.prev 72 | if l.tail == nil { 73 | l.head = nil 74 | } 75 | } 76 | return v, err 77 | } 78 | 79 | func main() { 80 | dashes := strings.Repeat("-", 50) 81 | l := new(List) // Create Doubly Linked List 82 | 83 | l.Push(Value{Name: "Atlanta", MilesAway: 0}) 84 | l.Push(Value{Name: "Las Vegas", MilesAway: 1961}) 85 | l.Push(Value{Name: "New York", MilesAway: 881}) 86 | 87 | processed := make(map[*Node]bool) 88 | 89 | fmt.Println("First time through list...") 90 | for n := l.First(); n != nil; n = n.Next() { 91 | fmt.Printf("%v\n", n.Value) 92 | if processed[n] { 93 | fmt.Printf("%s as been processed\n", n.Value) 94 | } 95 | processed[n] = true 96 | } 97 | fmt.Println(dashes) 98 | fmt.Println("Second time through list...") 99 | for n := l.First(); n != nil; n = n.Next() { 100 | fmt.Printf("%v", n.Value) 101 | if processed[n] { 102 | fmt.Println(" has been processed") 103 | } else { fmt.Println() } 104 | processed[n] = true 105 | } 106 | 107 | fmt.Println(dashes) 108 | var found_node *Node 109 | city_to_find := "New York" 110 | found_node = l.Find(city_to_find) 111 | if found_node == nil { 112 | fmt.Printf("NOT FOUND: %v\n", city_to_find) 113 | } else { 114 | fmt.Printf("FOUND: %v\n", city_to_find) 115 | } 116 | 117 | city_to_find = "Chicago" 118 | found_node = l.Find(city_to_find) 119 | if found_node == nil { 120 | fmt.Printf("NOT FOUND: %v\n", city_to_find) 121 | } else { 122 | fmt.Printf("FOUND: %v\n", city_to_find) 123 | } 124 | 125 | fmt.Println(dashes) 126 | city_to_remove := "Las Vegas" 127 | successfully_removed_city := l.Delete(city_to_remove) 128 | if successfully_removed_city { 129 | fmt.Printf("REMOVED: %v\n", city_to_remove) 130 | } else { 131 | fmt.Printf("DID NOT REMOVE: %v\n", city_to_remove) 132 | } 133 | 134 | city_to_remove = "Chicago" 135 | successfully_removed_city = l.Delete(city_to_remove) 136 | if successfully_removed_city { 137 | fmt.Printf("REMOVED: %v\n", city_to_remove) 138 | } else { 139 | fmt.Printf("DID NOT REMOVE: %v\n", city_to_remove) 140 | } 141 | 142 | fmt.Println(dashes) 143 | fmt.Println("* Pop each value off list...") 144 | for v, err := l.Pop(); err == nil; v, err = l.Pop() { 145 | fmt.Printf("%v\n", v) 146 | } 147 | fmt.Println(l.Pop()) // Generate error - attempt to pop from empty list 148 | } -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/go/index.ts: -------------------------------------------------------------------------------- 1 | import { StreamLanguage } from '@codemirror/language' 2 | import { go } from '@codemirror/legacy-modes/mode/go' 3 | import code from './go.go?raw' 4 | 5 | export default { 6 | language: () => StreamLanguage.define(go), 7 | code 8 | } 9 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/html/html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mixed HTML Example 5 | 18 | 19 | 20 |

Mixed HTML Example

21 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/html/index.ts: -------------------------------------------------------------------------------- 1 | import { html } from '@codemirror/lang-html' 2 | import code from './html.html?raw' 3 | 4 | export default { 5 | language: html, 6 | code 7 | } 8 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/java/index.ts: -------------------------------------------------------------------------------- 1 | import { java } from '@codemirror/lang-java' 2 | import code from './java.java?raw' 3 | 4 | export default { 5 | language: java, 6 | code 7 | } 8 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/java/java.java: -------------------------------------------------------------------------------- 1 | /* 2 | Basic Java example using FizzBuzz 3 | */ 4 | 5 | import java.util.Random; 6 | 7 | public class Example { 8 | public static void main (String[] args){ 9 | // Generate a random number between 1-100. (See generateRandomNumber method.) 10 | int random = generateRandomNumber(100); 11 | 12 | // Output generated number. 13 | System.out.println("Generated number: " + random + "\n"); 14 | 15 | // Loop between 1 and the number we just generated. 16 | for (int i=1; i<=random; i++){ 17 | // If i is divisible by both 3 and 5, output "FizzBuzz". 18 | if (i % 3 == 0 && i % 5 == 0){ 19 | System.out.println("FizzBuzz"); 20 | } 21 | // If i is divisible by 3, output "Fizz" 22 | else if (i % 3 == 0){ 23 | System.out.println("Fizz"); 24 | } 25 | // If i is divisible by 5, output "Buzz". 26 | else if (i % 5 == 0){ 27 | System.out.println("Buzz"); 28 | } 29 | // If i is not divisible by either 3 or 5, output the number. 30 | else { 31 | System.out.println(i); 32 | } 33 | } 34 | } 35 | 36 | /** 37 | Generates a new random number between 0 and 100. 38 | @param bound The highest number that should be generated. 39 | @return An integer representing a randomly generated number between 0 and 100. 40 | */ 41 | private static int generateRandomNumber(int bound){ 42 | // Create new Random generator object and generate the random number. 43 | Random randGen = new Random(); 44 | int randomNum = randGen.nextInt(bound); 45 | 46 | // If the random number generated is zero, use recursion to regenerate the number until it is not zero. 47 | if (randomNum < 1){ 48 | randomNum = generateRandomNumber(bound); 49 | } 50 | 51 | return randomNum; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/javascript/index.ts: -------------------------------------------------------------------------------- 1 | import { javascript } from '@codemirror/lang-javascript' 2 | import code from './javascript.js?raw' 3 | 4 | export default { 5 | language: javascript, 6 | code 7 | } 8 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/javascript/javascript.js: -------------------------------------------------------------------------------- 1 | // Demo code (the actual new parser character stream implementation) 2 | 3 | function StringStream(string) { 4 | this.pos = 0 5 | this.string = string 6 | } 7 | 8 | StringStream.prototype = { 9 | done: function () { 10 | return this.pos >= this.string.length 11 | }, 12 | peek: function () { 13 | return this.string.charAt(this.pos) 14 | }, 15 | next: function () { 16 | if (this.pos < this.string.length) return this.string.charAt(this.pos++) 17 | }, 18 | eat: function (match) { 19 | var ch = this.string.charAt(this.pos) 20 | if (typeof match == 'string') var ok = ch == match 21 | else var ok = ch && match.test ? match.test(ch) : match(ch) 22 | if (ok) { 23 | this.pos++ 24 | return ch 25 | } 26 | }, 27 | eatWhile: function (match) { 28 | var start = this.pos 29 | while (this.eat(match)); 30 | if (this.pos > start) return this.string.slice(start, this.pos) 31 | }, 32 | backUp: function (n) { 33 | this.pos -= n 34 | }, 35 | column: function () { 36 | return this.pos 37 | }, 38 | eatSpace: function () { 39 | var start = this.pos 40 | while (/\s/.test(this.string.charAt(this.pos))) this.pos++ 41 | return this.pos - start 42 | }, 43 | match: function (pattern, consume, caseInsensitive) { 44 | if (typeof pattern == 'string') { 45 | function cased(str) { 46 | return caseInsensitive ? str.toLowerCase() : str 47 | } 48 | if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) { 49 | if (consume !== false) this.pos += str.length 50 | return true 51 | } 52 | } else { 53 | var match = this.string.slice(this.pos).match(pattern) 54 | if (match && consume !== false) this.pos += match[0].length 55 | return match 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/json/index.ts: -------------------------------------------------------------------------------- 1 | import { json } from '@codemirror/lang-json' 2 | import code from './json.json?raw' 3 | 4 | export default { 5 | language: json, 6 | code 7 | } 8 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/json/json.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true, 7 | "members": [ 8 | { 9 | "name": "Molecule Man", 10 | "age": 29, 11 | "secretIdentity": "Dan Jukes", 12 | "powers": ["Radiation resistance", "Turning tiny", "Radiation blast"] 13 | }, 14 | { 15 | "name": "Madame Uppercut", 16 | "age": 39, 17 | "secretIdentity": "Jane Wilson", 18 | "powers": ["Million tonne punch", "Damage resistance", "Superhuman reflexes"] 19 | }, 20 | { 21 | "name": "Eternal Flame", 22 | "age": 1000000, 23 | "secretIdentity": "Unknown", 24 | "powers": [ 25 | "Immortality", 26 | "Heat Immunity", 27 | "Inferno", 28 | "Teleportation", 29 | "Interdimensional travel" 30 | ] 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/jsx/index.ts: -------------------------------------------------------------------------------- 1 | import { javascript } from '@codemirror/lang-javascript' 2 | import code from './jsx.jsx?raw' 3 | 4 | export default { 5 | language: () => javascript({ jsx: true }), 6 | code 7 | } 8 | -------------------------------------------------------------------------------- /src/renderer/src/codemirror/lang-code/jsx/jsx.jsx: -------------------------------------------------------------------------------- 1 | // Code snippets from http://facebook.github.io/react/docs/jsx-in-depth.html 2 | 3 | // Rendering HTML tags 4 | var myDivElement =
5 | ReactDOM.render(myDivElement, document.getElementById('example')) 6 | 7 | // Rendering React components 8 | var MyComponent = React.createClass({ 9 | /*...*/ 10 | }) 11 | var myElement = 12 | ReactDOM.render(myElement, document.getElementById('example')) 13 | 14 | // Namespaced components 15 | var Form = MyFormComponent 16 | 17 | var App = ( 18 |
19 | 20 | 21 | 22 | 23 |
24 | ) 25 | 26 | // Attribute JavaScript expressions 27 | var person = 28 | 29 | // Boolean attributes 30 | ; 31 | ; 32 | 33 | // Child JavaScript expressions 34 | var content = {window.isLoggedIn ?