Skip to content

Commit

Permalink
Merge branch 'master' into fix/dsl-query-boolean-operators
Browse files Browse the repository at this point in the history
  • Loading branch information
logseq-cldwalker committed Mar 4, 2022
2 parents 12395c6 + b260648 commit 3987395
Show file tree
Hide file tree
Showing 29 changed files with 564 additions and 365 deletions.
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
thheller/shadow-cljs {:mvn/version "2.17.5"}
expound/expound {:mvn/version "0.8.6"}
com.lambdaisland/glogi {:mvn/version "1.1.144"}
binaryage/devtools {:mvn/version "1.0.2"}
binaryage/devtools {:mvn/version "1.0.5"}
camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.2"}
instaparse/instaparse {:mvn/version "1.4.10"}
nubank/workspaces {:mvn/version "1.1.1"}
Expand Down
8 changes: 8 additions & 0 deletions docs/dev-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,11 @@ appear where shadow-cljs was first invoked e.g. where `yarn watch` is running.
Specific namespace(s) can be auto run with the `:ns-regexp` option e.g. `npx
shadow-cljs watch test --config-merge '{:autorun true :ns-regexp
"frontend.text-test"}'`.

## Logging

For logging, we use https://github.com/lambdaisland/glogi. When in development,
be sure to have [enabled custom
formatters](https://github.com/binaryage/cljs-devtools/blob/master/docs/installation.md#enable-custom-formatters-in-chrome)
in the desktop app and browser. Without this enabled, most of the log messages
aren't readable.
8 changes: 8 additions & 0 deletions ios/App/App.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
D32752BE275496C60039291C /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D32752BD275496C60039291C /* CloudKit.framework */; };
D3D62A0A275C92880003FBDC /* FileContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3D62A09275C92880003FBDC /* FileContainer.swift */; };
D3D62A0C275C928F0003FBDC /* FileContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = D3D62A0B275C928F0003FBDC /* FileContainer.m */; };
FE647FF427BDFEDE00F3206B /* FsWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE647FF327BDFEDE00F3206B /* FsWatcher.swift */; };
FE647FF627BDFEF500F3206B /* FsWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = FE647FF527BDFEF500F3206B /* FsWatcher.m */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -47,6 +49,8 @@
D3D62A09275C92880003FBDC /* FileContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileContainer.swift; sourceTree = "<group>"; };
D3D62A0B275C928F0003FBDC /* FileContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileContainer.m; sourceTree = "<group>"; };
DE5650F4AD4E2242AB9C012D /* Pods-Logseq.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Logseq.debug.xcconfig"; path = "Target Support Files/Pods-Logseq/Pods-Logseq.debug.xcconfig"; sourceTree = "<group>"; };
FE647FF327BDFEDE00F3206B /* FsWatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FsWatcher.swift; sourceTree = "<group>"; };
FE647FF527BDFEF500F3206B /* FsWatcher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FsWatcher.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -96,6 +100,8 @@
2FAD9762203C412B000D30F8 /* config.xml */,
50B271D01FEDC1A000F3C39B /* public */,
7435D10B2704659F00AB88E0 /* FolderPicker.swift */,
FE647FF327BDFEDE00F3206B /* FsWatcher.swift */,
FE647FF527BDFEF500F3206B /* FsWatcher.m */,
7435D10E2704660B00AB88E0 /* FolderPicker.m */,
D3D62A09275C92880003FBDC /* FileContainer.swift */,
D3D62A0B275C928F0003FBDC /* FileContainer.m */,
Expand Down Expand Up @@ -241,11 +247,13 @@
files = (
504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
5FD5BB71278579F5008E6875 /* DownloadiCloudFiles.swift in Sources */,
FE647FF427BDFEDE00F3206B /* FsWatcher.swift in Sources */,
5FD5BB73278579FF008E6875 /* DownloadiCloudFiles.m in Sources */,
D3D62A0A275C92880003FBDC /* FileContainer.swift in Sources */,
D3D62A0C275C928F0003FBDC /* FileContainer.m in Sources */,
7435D10F2704660B00AB88E0 /* FolderPicker.m in Sources */,
7435D10C2704659F00AB88E0 /* FolderPicker.swift in Sources */,
FE647FF627BDFEF500F3206B /* FsWatcher.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 1 addition & 1 deletion ios/App/App/DownloadiCloudFiles.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// DowloadiCloudFiles.m
// DownloadiCloudFiles.m
// Logseq
//
// Created by leizhe on 2021/12/29.
Expand Down
6 changes: 2 additions & 4 deletions ios/App/App/FileContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class FileContainer: CAPPlugin, UIDocumentPickerDelegate {
guard let filename = self.containerUrl?.appendingPathComponent(".logseq") else {
return
}

if !FileManager.default.fileExists(atPath: filename.path) {
do {
try str.write(to: filename, atomically: true, encoding: String.Encoding.utf8)
Expand All @@ -45,8 +45,6 @@ public class FileContainer: CAPPlugin, UIDocumentPickerDelegate {
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
}
}
self._call?.resolve([
"path": self.containerUrl?.path
])
self._call?.resolve(["path": self.containerUrl?.path as Any])
}
}
13 changes: 13 additions & 0 deletions ios/App/App/FsWatcher.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// FsWatcher.m
// Logseq
//
// Created by Mono Wang on 2/17/R4.
//

#import <Capacitor/Capacitor.h>

CAP_PLUGIN(FsWatcher, "FsWatcher",
CAP_PLUGIN_METHOD(watch, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(unwatch, CAPPluginReturnPromise);
)
222 changes: 222 additions & 0 deletions ios/App/App/FsWatcher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
//
// FsWatcher.swift
// Logseq
//
// Created by Mono Wang on 2/17/R4.
//

import Foundation
import Capacitor

// MARK: Watcher Plugin

@objc(FsWatcher)
public class FsWatcher: CAPPlugin, PollingWatcherDelegate {
private var watcher: PollingWatcher? = nil
private var baseUrl: URL? = nil

override public func load() {
print("debug FsWatcher iOS plugin loaded!")
}

@objc func watch(_ call: CAPPluginCall) {
if let path = call.getString("path") {
guard let url = URL(string: path) else {
call.reject("can not parse url")
return
}
self.baseUrl = url
self.watcher = PollingWatcher(at: url)
self.watcher?.delegate = self

call.resolve(["ok": true])

} else {
call.reject("missing path string parameter")
}
}

@objc func unwatch(_ call: CAPPluginCall) {
watcher?.stop()
watcher = nil
baseUrl = nil

call.resolve()
}

public func recevedNotification(_ url: URL, _ event: PollingWatcherEvent, _ metadata: SimpleFileMetadata?) {
// NOTE: Event in js {dir path content stat{mtime}}
switch event {
case .Unlink:
self.notifyListeners("watcher", data: ["event": "unlink",
"dir": baseUrl?.description as Any,
"path": url.description,
])
case .Add:
let content = try? String(contentsOf: url, encoding: .utf8)
self.notifyListeners("watcher", data: ["event": "add",
"dir": baseUrl?.description as Any,
"path": url.description,
"content": content as Any,
"stat": ["mtime": metadata?.contentModificationTimestamp,
"ctime": metadata?.creationTimestamp]
])
case .Change:
let content = try? String(contentsOf: url, encoding: .utf8)
self.notifyListeners("watcher", data: ["event": "change",
"dir": baseUrl?.description as Any,
"path": url.description,
"content": content as Any,
"stat": ["mtime": metadata?.contentModificationTimestamp,
"ctime": metadata?.creationTimestamp]])
case .Error:
// TODO: handle error?
break
}
}
}

// MARK: URL extension

extension URL {
func isSkipped() -> Bool {
// skip hidden file
if self.lastPathComponent.starts(with: ".") {
return true
}
let allowedPathExtensions: Set = ["md", "markdown", "org", "css", "edn", "excalidraw"]
if allowedPathExtensions.contains(self.pathExtension.lowercased()) {
return false
}
// skip for other file types
return true
}

func isICloudPlaceholder() -> Bool {
if self.lastPathComponent.starts(with: ".") && self.pathExtension.lowercased() == "icloud" {
return true
}
return false
}
}

// MARK: PollingWatcher

public protocol PollingWatcherDelegate {
func recevedNotification(_ url: URL, _ event: PollingWatcherEvent, _ metadata: SimpleFileMetadata?)
}

public enum PollingWatcherEvent: String {
case Add
case Change
case Unlink
case Error
}

public struct SimpleFileMetadata: CustomStringConvertible, Equatable {
var contentModificationTimestamp: Double
var creationTimestamp: Double
var fileSize: Int

public init?(of fileURL: URL) {
do {
let fileAttributes = try fileURL.resourceValues(forKeys:[.isRegularFileKey, .fileSizeKey, .contentModificationDateKey, .creationDateKey])
if fileAttributes.isRegularFile! {
contentModificationTimestamp = fileAttributes.contentModificationDate?.timeIntervalSince1970 ?? 0.0
creationTimestamp = fileAttributes.creationDate?.timeIntervalSince1970 ?? 0.0
fileSize = fileAttributes.fileSize ?? 0
} else {
return nil
}
} catch {
return nil
}
}

public var description: String {
return "Meta(size=\(self.fileSize), mtime=\(self.contentModificationTimestamp), ctime=\(self.creationTimestamp)"
}
}

public class PollingWatcher {
private let url: URL
private var timer: DispatchSourceTimer?
public var delegate: PollingWatcherDelegate? = nil
private var metaDb: [URL: SimpleFileMetadata] = [:]

public init?(at: URL) {
url = at

let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".timer")
timer = DispatchSource.makeTimerSource(queue: queue)
timer!.setEventHandler(qos: .background, flags: []) { [weak self] in
self?.tick()
}
timer!.schedule(deadline: .now())
timer!.resume()

}

deinit {
self.stop()
}

public func stop() {
timer?.cancel()
timer = nil
}

private func tick() {
let startTime = DispatchTime.now()

if let enumerator = FileManager.default.enumerator(
at: url,
includingPropertiesForKeys: [.isRegularFileKey],
// NOTE: icloud downloading requires non-skipsHiddenFiles
options: [.skipsPackageDescendants]) {

var newMetaDb: [URL: SimpleFileMetadata] = [:]

for case let fileURL as URL in enumerator {
if !fileURL.isSkipped() {
if let meta = SimpleFileMetadata(of: fileURL) {
newMetaDb[fileURL] = meta
}
} else if fileURL.isICloudPlaceholder() {
try? FileManager.default.startDownloadingUbiquitousItem(at: fileURL)
}
}

self.updateMetaDb(with: newMetaDb)
}

let elapsedNanoseconds = DispatchTime.now().uptimeNanoseconds - startTime.uptimeNanoseconds
let elapsedInMs = Double(elapsedNanoseconds) / 1_000_000
print("debug ticker elapsed=\(elapsedInMs)ms")

if #available(iOS 13.0, *) {
timer!.schedule(deadline: .now().advanced(by: .seconds(2)), leeway: .milliseconds(100))
} else {
// Fallback on earlier versions
timer!.schedule(deadline: .now() + 2.0, leeway: .milliseconds(100))
}
}

// TODO: batch?
private func updateMetaDb(with newMetaDb: [URL: SimpleFileMetadata]) {
for (url, meta) in newMetaDb {
if let idx = self.metaDb.index(forKey: url) {
let (_, oldMeta) = self.metaDb.remove(at: idx)
if oldMeta != meta {
self.delegate?.recevedNotification(url, .Change, meta)
}
} else {
self.delegate?.recevedNotification(url, .Add, meta)
}
}
for url in self.metaDb.keys {
self.delegate?.recevedNotification(url, .Unlink, nil)
}
self.metaDb = newMetaDb
}
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,15 @@
"ignore": "5.1.8",
"is-svg": "4.3.0",
"jszip": "3.5.0",
"mldoc": "1.3.1",
"mldoc": "1.3.2",
"path": "0.12.7",
"pixi-graph-fork": "0.2.0",
"pixi.js": "6.2.0",
"posthog-js": "1.10.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-grid-layout": "0.16.6",
"react-icon-base": "^2.1.2",
"react-icons": "2.2.7",
"react-resize-context": "3.0.0",
"react-textarea-autosize": "8.3.3",
Expand Down
2 changes: 2 additions & 0 deletions shadow-cljs.edn
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
:output-to "static/tests.js"
:closure-defines {frontend.util/NODETEST true}
:devtools {:enabled false}
;; disable :static-fns to allow for with-redefs and repl development
:compiler-options {:static-fns false}
:main frontend.node-test-runner/main}

:publishing {:target :browser
Expand Down
2 changes: 1 addition & 1 deletion src/main/frontend/commands.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@
(count (util/safe-re-find re-pattern prefix))))
new-value (str (subs edit-content 0 pos)
(string/replace-first (subs edit-content pos)
marker/marker-pattern
(marker/marker-pattern format)
(str marker " ")))]
(state/set-edit-content! input-id new-value)
(let [new-pos (compute-pos-delta-when-change-marker
Expand Down
Loading

0 comments on commit 3987395

Please sign in to comment.