mirror of
https://github.com/marktext/marktext.git
synced 2025-05-02 22:22:18 +08:00
refactor: main filesystem code (#1104)
This commit is contained in:
parent
1a92d2de1b
commit
ddc99aa00e
20
.github/CONTRIBUTING.md
vendored
20
.github/CONTRIBUTING.md
vendored
@ -114,16 +114,22 @@ For more scripts please see `package.json`.
|
|||||||
|
|
||||||
- ES6 and "best practices"
|
- ES6 and "best practices"
|
||||||
- 2 space indent
|
- 2 space indent
|
||||||
|
- no semicolons
|
||||||
- JSDoc for documentation
|
- JSDoc for documentation
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
- root: Configuration files
|
- `.`: Configuration files
|
||||||
- `package.json`: Project settings
|
- `package.json`: Project settings
|
||||||
- `build`: Contains generated binaries
|
- `build/`: Contains generated binaries
|
||||||
- `dist`: Build files for deployment
|
- `dist/`: Build files for deployment
|
||||||
- `docs`: Documentation and assets
|
- `docs/`: Documentation and assets
|
||||||
- `node_modules`: Dependencies
|
- `resources/`: Application assets using at build time
|
||||||
|
- `node_modules/`: Dependencies
|
||||||
- `src`: Mark Text source code
|
- `src`: Mark Text source code
|
||||||
- `static`: Application assets (images, themes, etc)
|
- `common/`: Common source files that only require Node.js APIs. Code from this folder can be used in all other folders except `muya`.
|
||||||
- `test`: Contains (unit) tests
|
- `main/`: Main process source files that require Electron main-process APIs. `main` files can use `common` source code.
|
||||||
|
- `muya/`: Mark Texts backend that only allow pure JavaScript, BOM and DOM APIs. Don't use Electron or Node.js APIs!
|
||||||
|
- `renderer`: Fontend that require Electron renderer-process APIs and may use `common` or `muya` source code.
|
||||||
|
- `static/`: Application assets (images, themes, etc)
|
||||||
|
- `test/`: Contains (unit) tests
|
||||||
|
71
src/common/filesystem/index.js
Normal file
71
src/common/filesystem/index.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether or not the given path exists.
|
||||||
|
*
|
||||||
|
* @param {string} p The path to the file or directory.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export const exists = async p => {
|
||||||
|
// Nodes fs.exists is deprecated.
|
||||||
|
try {
|
||||||
|
await fs.access(p)
|
||||||
|
return true
|
||||||
|
} catch(_) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that a directory exist.
|
||||||
|
*
|
||||||
|
* @param {string} dirPath The directory path.
|
||||||
|
*/
|
||||||
|
export const ensureDirSync = dirPath => {
|
||||||
|
try {
|
||||||
|
fs.ensureDirSync(dirPath)
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code !== 'EEXIST') {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the path is a directory with read access.
|
||||||
|
*
|
||||||
|
* @param {string} dirPath The directory path.
|
||||||
|
*/
|
||||||
|
export const isDirectory = dirPath => {
|
||||||
|
try {
|
||||||
|
return fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory()
|
||||||
|
} catch (_) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the path is a file with read access.
|
||||||
|
*
|
||||||
|
* @param {string} filepath The file path.
|
||||||
|
*/
|
||||||
|
export const isFile = filepath => {
|
||||||
|
try {
|
||||||
|
return fs.existsSync(filepath) && fs.lstatSync(filepath).isFile()
|
||||||
|
} catch (_) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the path is a symbolic link with read access.
|
||||||
|
*
|
||||||
|
* @param {string} filepath The link path.
|
||||||
|
*/
|
||||||
|
export const isSymbolicLink = filepath => {
|
||||||
|
try {
|
||||||
|
return fs.existsSync(filepath) && fs.lstatSync(filepath).isSymbolicLink()
|
||||||
|
} catch (_) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
116
src/common/filesystem/paths.js
Normal file
116
src/common/filesystem/paths.js
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import fs from 'fs-extra'
|
||||||
|
import path from 'path'
|
||||||
|
import { isFile, isSymbolicLink } from './index'
|
||||||
|
|
||||||
|
export const MARKDOWN_EXTENSIONS = [
|
||||||
|
'markdown',
|
||||||
|
'mdown',
|
||||||
|
'mkdn',
|
||||||
|
'md',
|
||||||
|
'mkd',
|
||||||
|
'mdwn',
|
||||||
|
'mdtxt',
|
||||||
|
'mdtext',
|
||||||
|
'text',
|
||||||
|
'txt'
|
||||||
|
]
|
||||||
|
|
||||||
|
export const IMAGE_EXTENSIONS = [
|
||||||
|
'jpeg',
|
||||||
|
'jpg',
|
||||||
|
'png',
|
||||||
|
'gif',
|
||||||
|
'svg',
|
||||||
|
'webp'
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the filename matches one of the markdown extensions.
|
||||||
|
*
|
||||||
|
* @param {string} filename Path or filename
|
||||||
|
*/
|
||||||
|
export const hasMarkdownExtension = filename => {
|
||||||
|
if (!filename || typeof filename !== 'string') return false
|
||||||
|
return MARKDOWN_EXTENSIONS.some(ext => filename.endsWith(`.${ext}`))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns ture if the path is an image file.
|
||||||
|
*
|
||||||
|
* @param {string} filepath The path
|
||||||
|
*/
|
||||||
|
export const isImageFile = filepath => {
|
||||||
|
const extname = path.extname(filepath)
|
||||||
|
return isFile(filepath) && IMAGE_EXTENSIONS.some(ext => {
|
||||||
|
const EXT_REG = new RegExp(ext, 'i')
|
||||||
|
return EXT_REG.test(extname)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the path is a markdown file.
|
||||||
|
*
|
||||||
|
* @param {string} filepath The path or link path.
|
||||||
|
*/
|
||||||
|
export const isMarkdownFile = filepath => {
|
||||||
|
return isFile(filepath) && hasMarkdownExtension(filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the path is a markdown file or symbolic link to a markdown file.
|
||||||
|
*
|
||||||
|
* @param {string} filepath The path or link path.
|
||||||
|
*/
|
||||||
|
export const isMarkdownFileOrLink = filepath => {
|
||||||
|
if (!isFile(filepath)) return false
|
||||||
|
if (hasMarkdownExtension(filepath)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Symbolic link to a markdown file
|
||||||
|
if (isSymbolicLink(filepath)) {
|
||||||
|
const targetPath = fs.readlinkSync(filepath)
|
||||||
|
return isFile(targetPath) && hasMarkdownExtension(targetPath)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the both paths point to the same file.
|
||||||
|
*
|
||||||
|
* @param {string} pathA The first path.
|
||||||
|
* @param {string} pathB The second path.
|
||||||
|
* @param {boolean} [isNormalized] Are both paths already normalized.
|
||||||
|
*/
|
||||||
|
export const isSamePathSync = (pathA, pathB, isNormalized = false) => {
|
||||||
|
if (!pathA || !pathB) return false
|
||||||
|
const a = isNormalized ? pathA : path.normalize(pathA)
|
||||||
|
const b = isNormalized ? pathB : path.normalize(pathB)
|
||||||
|
if (a.length !== b.length) {
|
||||||
|
return false
|
||||||
|
} else if (a === b) {
|
||||||
|
return true
|
||||||
|
} else if (a.toLowerCase() === b.toLowerCase()) {
|
||||||
|
try {
|
||||||
|
const fiA = fs.statSync(a)
|
||||||
|
const fiB = fs.statSync(b)
|
||||||
|
return fiA.ino === fiB.ino
|
||||||
|
} catch (_) {
|
||||||
|
// Ignore error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a file or directory is a child of the given directory.
|
||||||
|
*
|
||||||
|
* @param {string} dir The parent directory.
|
||||||
|
* @param {string} child The file or directory path to check.
|
||||||
|
*/
|
||||||
|
export const isChildOfDirectory = (dir, child) => {
|
||||||
|
if (!dir || !child) return false
|
||||||
|
const relative = path.relative(dir, child)
|
||||||
|
return relative && !relative.startsWith('..') && !path.isAbsolute(relative)
|
||||||
|
}
|
@ -4,9 +4,9 @@ import { exec } from 'child_process'
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import log from 'electron-log'
|
import log from 'electron-log'
|
||||||
import { app, BrowserWindow, clipboard, dialog, ipcMain, systemPreferences } from 'electron'
|
import { app, BrowserWindow, clipboard, dialog, ipcMain, systemPreferences } from 'electron'
|
||||||
|
import { isChildOfDirectory } from 'common/filesystem/paths'
|
||||||
import { isLinux, isOsx } from '../config'
|
import { isLinux, isOsx } from '../config'
|
||||||
import parseArgs from '../cli/parser'
|
import parseArgs from '../cli/parser'
|
||||||
import { isChildOfDirectory } from '../filesystem'
|
|
||||||
import { normalizeMarkdownPath } from '../filesystem/markdown'
|
import { normalizeMarkdownPath } from '../filesystem/markdown'
|
||||||
import { getMenuItemById } from '../menu'
|
import { getMenuItemById } from '../menu'
|
||||||
import { selectTheme } from '../menu/actions/theme'
|
import { selectTheme } from '../menu/actions/theme'
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import EnvPaths from 'common/envPaths'
|
import EnvPaths from 'common/envPaths'
|
||||||
import { ensureDirSync } from '../filesystem'
|
import { ensureDirSync } from 'common/filesystem'
|
||||||
|
|
||||||
class AppPaths extends EnvPaths {
|
class AppPaths extends EnvPaths {
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import os from 'os'
|
import os from 'os'
|
||||||
import { isDirectory } from '../filesystem'
|
import { isDirectory } from 'common/filesystem'
|
||||||
import parseArgs from './parser'
|
import parseArgs from './parser'
|
||||||
import { dumpKeyboardInformation } from '../keyboard'
|
import { dumpKeyboardInformation } from '../keyboard'
|
||||||
import { getPath } from '../utils'
|
import { getPath } from '../utils'
|
||||||
|
@ -34,28 +34,6 @@ export const defaultPreferenceWinOptions = {
|
|||||||
titleBarStyle: 'hiddenInset'
|
titleBarStyle: 'hiddenInset'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EXTENSIONS = [
|
|
||||||
'markdown',
|
|
||||||
'mdown',
|
|
||||||
'mkdn',
|
|
||||||
'md',
|
|
||||||
'mkd',
|
|
||||||
'mdwn',
|
|
||||||
'mdtxt',
|
|
||||||
'mdtext',
|
|
||||||
'text',
|
|
||||||
'txt'
|
|
||||||
]
|
|
||||||
|
|
||||||
export const IMAGE_EXTENSIONS = [
|
|
||||||
'jpeg',
|
|
||||||
'jpg',
|
|
||||||
'png',
|
|
||||||
'gif',
|
|
||||||
'svg',
|
|
||||||
'webp'
|
|
||||||
]
|
|
||||||
|
|
||||||
export const PANDOC_EXTENSIONS = [
|
export const PANDOC_EXTENSIONS = [
|
||||||
'html',
|
'html',
|
||||||
'docx',
|
'docx',
|
||||||
@ -72,12 +50,6 @@ export const PANDOC_EXTENSIONS = [
|
|||||||
'epub'
|
'epub'
|
||||||
]
|
]
|
||||||
|
|
||||||
// export const PROJECT_BLACK_LIST = [
|
|
||||||
// 'node_modules',
|
|
||||||
// '.git',
|
|
||||||
// '.DS_Store'
|
|
||||||
// ]
|
|
||||||
|
|
||||||
export const BLACK_LIST = [
|
export const BLACK_LIST = [
|
||||||
'$RECYCLE.BIN'
|
'$RECYCLE.BIN'
|
||||||
]
|
]
|
||||||
|
@ -6,8 +6,8 @@ import keytar from 'keytar'
|
|||||||
import schema from './schema'
|
import schema from './schema'
|
||||||
import Store from 'electron-store'
|
import Store from 'electron-store'
|
||||||
import log from 'electron-log'
|
import log from 'electron-log'
|
||||||
import { ensureDirSync } from '../filesystem'
|
import { ensureDirSync } from 'common/filesystem'
|
||||||
import { IMAGE_EXTENSIONS } from '../config'
|
import { IMAGE_EXTENSIONS } from 'common/filesystem/paths'
|
||||||
|
|
||||||
const DATA_CENTER_NAME = 'dataCenter'
|
const DATA_CENTER_NAME = 'dataCenter'
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ class DataCenter extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
* return a promise
|
* return a promise
|
||||||
*/
|
*/
|
||||||
|
@ -1,156 +1,6 @@
|
|||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { hasMarkdownExtension } from '../utils'
|
import { isDirectory, isFile, isSymbolicLink } from 'common/filesystem'
|
||||||
import { IMAGE_EXTENSIONS } from '../config'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether or not the given path exists.
|
|
||||||
*
|
|
||||||
* @param {string} p The path to the file or directory.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export const exists = async p => {
|
|
||||||
// fs.exists is deprecated.
|
|
||||||
try {
|
|
||||||
await fs.access(p)
|
|
||||||
return true
|
|
||||||
} catch(_) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure that a directory exist.
|
|
||||||
*
|
|
||||||
* @param {string} dirPath The directory path.
|
|
||||||
*/
|
|
||||||
export const ensureDirSync = dirPath => {
|
|
||||||
try {
|
|
||||||
fs.ensureDirSync(dirPath)
|
|
||||||
} catch (e) {
|
|
||||||
if (e.code !== 'EEXIST') {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the path is a directory with read access.
|
|
||||||
*
|
|
||||||
* @param {string} dirPath The directory path.
|
|
||||||
*/
|
|
||||||
export const isDirectory = dirPath => {
|
|
||||||
try {
|
|
||||||
return fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory()
|
|
||||||
} catch (_) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the path is a file with read access.
|
|
||||||
*
|
|
||||||
* @param {string} filepath The file path.
|
|
||||||
*/
|
|
||||||
export const isFile = filepath => {
|
|
||||||
try {
|
|
||||||
return fs.existsSync(filepath) && fs.lstatSync(filepath).isFile()
|
|
||||||
} catch (_) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the path is a symbolic link with read access.
|
|
||||||
*
|
|
||||||
* @param {string} filepath The link path.
|
|
||||||
*/
|
|
||||||
export const isSymbolicLink = filepath => {
|
|
||||||
try {
|
|
||||||
return fs.existsSync(filepath) && fs.lstatSync(filepath).isSymbolicLink()
|
|
||||||
} catch (_) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the path is a markdown file.
|
|
||||||
*
|
|
||||||
* @param {string} filepath The path or link path.
|
|
||||||
*/
|
|
||||||
export const isMarkdownFile = filepath => {
|
|
||||||
return isFile(filepath) && hasMarkdownExtension(filepath)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns ture if the path is an image file.
|
|
||||||
*
|
|
||||||
* @param {string} filepath The path
|
|
||||||
*/
|
|
||||||
export const isImageFile = filepath => {
|
|
||||||
const extname = path.extname(filepath)
|
|
||||||
return isFile(filepath) && IMAGE_EXTENSIONS.some(ext => {
|
|
||||||
const EXT_REG = new RegExp(ext, 'i')
|
|
||||||
return EXT_REG.test(extname)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the path is a markdown file or symbolic link to a markdown file.
|
|
||||||
*
|
|
||||||
* @param {string} filepath The path or link path.
|
|
||||||
*/
|
|
||||||
export const isMarkdownFileOrLink = filepath => {
|
|
||||||
if (!isFile(filepath)) return false
|
|
||||||
if (hasMarkdownExtension(filepath)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symbolic link to a markdown file
|
|
||||||
if (isSymbolicLink(filepath)) {
|
|
||||||
const targetPath = fs.readlinkSync(filepath)
|
|
||||||
return isFile(targetPath) && hasMarkdownExtension(targetPath)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the both paths point to the same file.
|
|
||||||
*
|
|
||||||
* @param {string} pathA The first path.
|
|
||||||
* @param {string} pathB The second path.
|
|
||||||
* @param {boolean} [isNormalized] Are both paths already normalized.
|
|
||||||
*/
|
|
||||||
export const isSamePathSync = (pathA, pathB, isNormalized = false) => {
|
|
||||||
if (!pathA || !pathB) return false
|
|
||||||
const a = isNormalized ? pathA : path.normalize(pathA)
|
|
||||||
const b = isNormalized ? pathB : path.normalize(pathB)
|
|
||||||
if (a.length !== b.length) {
|
|
||||||
return false
|
|
||||||
} else if (a === b) {
|
|
||||||
return true
|
|
||||||
} else if (a.toLowerCase() === b.toLowerCase()) {
|
|
||||||
try {
|
|
||||||
const fiA = fs.statSync(a)
|
|
||||||
const fiB = fs.statSync(b)
|
|
||||||
return fiA.ino === fiB.ino
|
|
||||||
} catch (_) {
|
|
||||||
// Ignore error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether a file or directory is a child of the given directory.
|
|
||||||
*
|
|
||||||
* @param {string} dir The parent directory.
|
|
||||||
* @param {string} child The file or directory path to check.
|
|
||||||
*/
|
|
||||||
export const isChildOfDirectory = (dir, child) => {
|
|
||||||
if (!dir || !child) return false
|
|
||||||
const relative = path.relative(dir, child)
|
|
||||||
return relative && !relative.startsWith('..') && !path.isAbsolute(relative)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the path into an absolute path and resolves the link target if needed.
|
* Normalize the path into an absolute path and resolves the link target if needed.
|
||||||
|
@ -2,7 +2,9 @@ import fs from 'fs-extra'
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import log from 'electron-log'
|
import log from 'electron-log'
|
||||||
import { LINE_ENDING_REG, LF_LINE_ENDING_REG, CRLF_LINE_ENDING_REG } from '../config'
|
import { LINE_ENDING_REG, LF_LINE_ENDING_REG, CRLF_LINE_ENDING_REG } from '../config'
|
||||||
import { isDirectory, isMarkdownFileOrLink, normalizeAndResolvePath , writeFile } from '../filesystem'
|
import { isDirectory } from 'common/filesystem'
|
||||||
|
import { isMarkdownFileOrLink } from 'common/filesystem/paths'
|
||||||
|
import { normalizeAndResolvePath, writeFile } from '../filesystem'
|
||||||
|
|
||||||
const getLineEnding = lineEnding => {
|
const getLineEnding = lineEnding => {
|
||||||
if (lineEnding === 'lf') {
|
if (lineEnding === 'lf') {
|
||||||
|
@ -2,8 +2,9 @@ import path from 'path'
|
|||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import log from 'electron-log'
|
import log from 'electron-log'
|
||||||
import chokidar from 'chokidar'
|
import chokidar from 'chokidar'
|
||||||
import { getUniqueId, hasMarkdownExtension } from '../utils'
|
import { exists } from 'common/filesystem'
|
||||||
import { exists } from '../filesystem'
|
import { hasMarkdownExtension } from 'common/filesystem/paths'
|
||||||
|
import { getUniqueId } from '../utils'
|
||||||
import { loadMarkdownFile } from '../filesystem/markdown'
|
import { loadMarkdownFile } from '../filesystem/markdown'
|
||||||
import { isLinux } from '../config'
|
import { isLinux } from '../config'
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ import path from 'path'
|
|||||||
import log from 'electron-log'
|
import log from 'electron-log'
|
||||||
import isAccelerator from 'electron-is-accelerator'
|
import isAccelerator from 'electron-is-accelerator'
|
||||||
import electronLocalshortcut from '@hfelix/electron-localshortcut'
|
import electronLocalshortcut from '@hfelix/electron-localshortcut'
|
||||||
|
import { isFile } from 'common/filesystem'
|
||||||
import { isOsx } from '../config'
|
import { isOsx } from '../config'
|
||||||
import { getKeyboardLanguage, getVirtualLetters } from '../keyboard'
|
import { getKeyboardLanguage, getVirtualLetters } from '../keyboard'
|
||||||
import { isFile } from '../filesystem'
|
|
||||||
|
|
||||||
// Problematic key bindings:
|
// Problematic key bindings:
|
||||||
// Aidou: Ctrl+/ -> dead key
|
// Aidou: Ctrl+/ -> dead key
|
||||||
|
@ -3,8 +3,10 @@ import path from 'path'
|
|||||||
import { promisify } from 'util'
|
import { promisify } from 'util'
|
||||||
import { BrowserWindow, dialog, ipcMain, shell } from 'electron'
|
import { BrowserWindow, dialog, ipcMain, shell } from 'electron'
|
||||||
import log from 'electron-log'
|
import log from 'electron-log'
|
||||||
import { EXTENSION_HASN, EXTENSIONS, PANDOC_EXTENSIONS, URL_REG } from '../../config'
|
import { isDirectory, isFile } from 'common/filesystem'
|
||||||
import { isDirectory, isFile, isMarkdownFile, isMarkdownFileOrLink, normalizeAndResolvePath, writeFile } from '../../filesystem'
|
import { MARKDOWN_EXTENSIONS, isMarkdownFile, isMarkdownFileOrLink } from 'common/filesystem/paths'
|
||||||
|
import { EXTENSION_HASN, PANDOC_EXTENSIONS, URL_REG } from '../../config'
|
||||||
|
import { normalizeAndResolvePath, writeFile } from '../../filesystem'
|
||||||
import { writeMarkdownFile } from '../../filesystem/markdown'
|
import { writeMarkdownFile } from '../../filesystem/markdown'
|
||||||
import { getPath, getRecommendTitleFromMarkdownString } from '../../utils'
|
import { getPath, getRecommendTitleFromMarkdownString } from '../../utils'
|
||||||
import pandoc from '../../utils/pandoc'
|
import pandoc from '../../utils/pandoc'
|
||||||
@ -417,7 +419,7 @@ export const openFile = win => {
|
|||||||
properties: ['openFile', 'multiSelections'],
|
properties: ['openFile', 'multiSelections'],
|
||||||
filters: [{
|
filters: [{
|
||||||
name: 'text',
|
name: 'text',
|
||||||
extensions: EXTENSIONS
|
extensions: MARKDOWN_EXTENSIONS
|
||||||
}]
|
}]
|
||||||
}, paths => {
|
}, paths => {
|
||||||
if (paths && Array.isArray(paths)) {
|
if (paths && Array.isArray(paths)) {
|
||||||
|
@ -2,8 +2,8 @@ import fs from 'fs'
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { app, ipcMain, Menu } from 'electron'
|
import { app, ipcMain, Menu } from 'electron'
|
||||||
import log from 'electron-log'
|
import log from 'electron-log'
|
||||||
|
import { ensureDirSync, isDirectory, isFile } from 'common/filesystem'
|
||||||
import { isLinux } from '../config'
|
import { isLinux } from '../config'
|
||||||
import { ensureDirSync, isDirectory, isFile } from '../filesystem'
|
|
||||||
import { parseMenu } from '../keyboard/shortcutHandler'
|
import { parseMenu } from '../keyboard/shortcutHandler'
|
||||||
import configureMenu, { configSettingMenu } from '../menu/templates'
|
import configureMenu, { configSettingMenu } from '../menu/templates'
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { shell } from 'electron'
|
import { shell } from 'electron'
|
||||||
|
import { isFile } from 'common/filesystem'
|
||||||
import * as actions from '../actions/help'
|
import * as actions from '../actions/help'
|
||||||
import { checkUpdates } from '../actions/marktext'
|
import { checkUpdates } from '../actions/marktext'
|
||||||
import { isFile } from '../../filesystem'
|
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const helpMenu = {
|
const helpMenu = {
|
||||||
|
@ -2,8 +2,9 @@ import fs from 'fs'
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { filter } from 'fuzzaldrin'
|
import { filter } from 'fuzzaldrin'
|
||||||
import log from 'electron-log'
|
import log from 'electron-log'
|
||||||
import { IMAGE_EXTENSIONS, BLACK_LIST } from '../config'
|
import { isDirectory, isFile } from 'common/filesystem'
|
||||||
import { isDirectory, isFile } from '../filesystem'
|
import { IMAGE_EXTENSIONS } from 'common/filesystem/paths'
|
||||||
|
import { BLACK_LIST } from '../config'
|
||||||
|
|
||||||
// TODO(need::refactor): Refactor this file. Just return an array of directories and files without caching and watching?
|
// TODO(need::refactor): Refactor this file. Just return an array of directories and files without caching and watching?
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import { EXTENSIONS } from '../config'
|
|
||||||
|
|
||||||
const ID_PREFIX = 'mt-'
|
const ID_PREFIX = 'mt-'
|
||||||
let id = 0
|
let id = 0
|
||||||
@ -37,16 +36,6 @@ export const getPath = name => {
|
|||||||
return app.getPath(name)
|
return app.getPath(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the filename matches one of the markdown extensions.
|
|
||||||
*
|
|
||||||
* @param {string} filename Path or filename
|
|
||||||
*/
|
|
||||||
export const hasMarkdownExtension = filename => {
|
|
||||||
if (!filename || typeof filename !== 'string') return false
|
|
||||||
return EXTENSIONS.some(ext => filename.endsWith(`.${ext}`))
|
|
||||||
}
|
|
||||||
|
|
||||||
export const hasSameKeys = (a, b) => {
|
export const hasSameKeys = (a, b) => {
|
||||||
const aKeys = Object.keys(a).sort()
|
const aKeys = Object.keys(a).sort()
|
||||||
const bKeys = Object.keys(b).sort()
|
const bKeys = Object.keys(b).sort()
|
||||||
|
@ -2,10 +2,10 @@ import path from 'path'
|
|||||||
import { BrowserWindow, dialog, ipcMain } from 'electron'
|
import { BrowserWindow, dialog, ipcMain } from 'electron'
|
||||||
import log from 'electron-log'
|
import log from 'electron-log'
|
||||||
import windowStateKeeper from 'electron-window-state'
|
import windowStateKeeper from 'electron-window-state'
|
||||||
|
import { isChildOfDirectory, isSamePathSync } from 'common/filesystem/paths'
|
||||||
import BaseWindow, { WindowLifecycle, WindowType } from './base'
|
import BaseWindow, { WindowLifecycle, WindowType } from './base'
|
||||||
import { ensureWindowPosition } from './utils'
|
import { ensureWindowPosition } from './utils'
|
||||||
import { TITLE_BAR_HEIGHT, editorWinOptions, isLinux, isOsx } from '../config'
|
import { TITLE_BAR_HEIGHT, editorWinOptions, isLinux, isOsx } from '../config'
|
||||||
import { isChildOfDirectory, isSamePathSync } from '../filesystem'
|
|
||||||
import { loadMarkdownFile } from '../filesystem/markdown'
|
import { loadMarkdownFile } from '../filesystem/markdown'
|
||||||
|
|
||||||
class EditorWindow extends BaseWindow {
|
class EditorWindow extends BaseWindow {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { clipboard, ipcRenderer, shell } from 'electron'
|
import { clipboard, ipcRenderer, shell } from 'electron'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import equal from 'deep-equal'
|
import equal from 'deep-equal'
|
||||||
|
import { isSamePathSync } from 'common/filesystem/paths'
|
||||||
import bus from '../bus'
|
import bus from '../bus'
|
||||||
import { hasKeys, getUniqueId } from '../util'
|
import { hasKeys, getUniqueId } from '../util'
|
||||||
import { isSamePathSync } from '../util/fileSystem'
|
|
||||||
import listToTree from '../util/listToTree'
|
import listToTree from '../util/listToTree'
|
||||||
import { createDocumentState, getOptionsFromState, getSingleFileState, getBlankFileState } from './help'
|
import { createDocumentState, getOptionsFromState, getSingleFileState, getBlankFileState } from './help'
|
||||||
import notice from '../services/notification'
|
import notice from '../services/notification'
|
||||||
|
@ -2,7 +2,7 @@ import path from 'path'
|
|||||||
import fse from 'fs-extra'
|
import fse from 'fs-extra'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import Octokit from '@octokit/rest'
|
import Octokit from '@octokit/rest'
|
||||||
import { isImageFile } from '../../main/filesystem'
|
import { isImageFile } from 'common/filesystem/paths'
|
||||||
import { dataURItoBlob, getContentHash } from './index'
|
import { dataURItoBlob, getContentHash } from './index'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
@ -22,33 +22,6 @@ export const rename = (src, dest) => {
|
|||||||
return fse.move(src, dest)
|
return fse.move(src, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the both paths point to the same file.
|
|
||||||
*
|
|
||||||
* @param {string} pathA The first path.
|
|
||||||
* @param {string} pathB The second path.
|
|
||||||
* @param {boolean} [isNormalized] Are both paths already normalized.
|
|
||||||
*/
|
|
||||||
export const isSamePathSync = (pathA, pathB, isNormalized = false) => {
|
|
||||||
if (!pathA || !pathB) return false
|
|
||||||
const a = isNormalized ? pathA : path.normalize(pathA)
|
|
||||||
const b = isNormalized ? pathB : path.normalize(pathB)
|
|
||||||
if (a.length !== b.length) {
|
|
||||||
return false
|
|
||||||
} else if (a === b) {
|
|
||||||
return true
|
|
||||||
} else if (a.toLowerCase() === b.toLowerCase()) {
|
|
||||||
try {
|
|
||||||
const fiA = fse.statSync(a)
|
|
||||||
const fiB = fse.statSync(b)
|
|
||||||
return fiA.ino === fiB.ino
|
|
||||||
} catch (_) {
|
|
||||||
// Ignore error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
export const moveImageToFolder = async (pathname, image, dir) => {
|
export const moveImageToFolder = async (pathname, image, dir) => {
|
||||||
const isPath = typeof image === 'string'
|
const isPath = typeof image === 'string'
|
||||||
if (isPath) {
|
if (isPath) {
|
||||||
|
Loading…
Reference in New Issue
Block a user