Live edit


In its simplest form you click a button and it loads a css and recursively calls setSkin on the UI. There should also be a way to listen to file changes in a predefined path. If a change is detected the change will affect the UI component it targets. Aka Live-edit. ==The Idea being that you could edit a .css file in Atom.io and have the Apps UI update immediately with-out recompiling the app==

img

==Another Live Edit example==: vimeo or dropbox

Here is the versatile ==FileWatcher kit== I made to facilitate the Live Editing feature: github

Research log:

  1. kFSEventStreamCreateFlagFileEvents: Request file-level notifications. Your stream will receive events about individual files in the hierarchy you’re watching instead of only receiving directory level notifications. Use this flag with care as it will generate significantly more events than without it.

  2. This lib has the key to making FSEvent instance based. The wrapper around FSEventStreamContext is able to pass on info to the callback, this way you could differentiate the NSNotification posts. here But its hard to understand the code and there is no guarantee that it will work in the end. So i’m moving on and just setting up

  3. seems like this repo is able to do instance based fsevents: here
  4. Seems to support multiple FileWatchers: SwiftFSWatcher

  5. a public weak var delegate: FilesystemEventListenerDelegate? could also maybe work? here

  6. Got fileWatching working with setting the closure to [weak self] more on that here

Example:

//Events to listen for: change,created,deleted,modified
/*
"MustScanSubDirs",
"UserDropped",
"KernelDropped",
"EventIdsWrapped",
"HistoryDone",
"RootChanged",
"Mount",
"Unmount",
"ItemCreated",
"ItemRemoved",
"ItemInodeMetaMod",
"ItemRenamed",
"ItemModified",
"ItemFinderInfoMod",
"ItemChangeOwner",
"ItemXattrMod",
"ItemIsFile",
"ItemIsDir",
"ItemIsSymlink",
"OwnEvent"
*/

enum {
   kFSEventStreamEventFlagNone = 0x00000000,
   kFSEventStreamEventFlagMustScanSubDirs = 0x00000001,
   kFSEventStreamEventFlagUserDropped = 0x00000002,
   kFSEventStreamEventFlagKernelDropped = 0x00000004,
   kFSEventStreamEventFlagEventIdsWrapped = 0x00000008,
   kFSEventStreamEventFlagHistoryDone = 0x00000010,
   kFSEventStreamEventFlagRootChanged = 0x00000020,
   kFSEventStreamEventFlagMount = 0x00000040,
   kFSEventStreamEventFlagUnmount = 0x00000080 , /* These flags are only set if you specified the FileEvents */
   /* flags when creating the stream.*/
   kFSEventStreamEventFlagItemCreated = 0x00000100,
   kFSEventStreamEventFlagItemRemoved = 0x00000200,
   kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400,
   kFSEventStreamEventFlagItemRenamed = 0x00000800,
   kFSEventStreamEventFlagItemModified = 0x00001000,
   kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000,
   kFSEventStreamEventFlagItemChangeOwner = 0x00004000,
   kFSEventStreamEventFlagItemXattrMod = 0x00008000,
   kFSEventStreamEventFlagItemIsFile = 0x00010000,
   kFSEventStreamEventFlagItemIsDir = 0x00020000,
   kFSEventStreamEventFlagItemIsSymlink = 0x00040000 
};

/*
Constants
kFSEventStreamEventFlagNone

There was some change in the directory at the specific path supplied in this event.

kFSEventStreamEventFlagMustScanSubDirs

Your application must rescan not just the directory given in the event, but all its children, recursively. This can happen if there was a problem whereby events were coalesced hierarchically. For example, an event in /Users/jsmith/Music and an event in /Users/jsmith/Pictures might be coalesced into an event with this flag set and path=/Users/jsmith. If this flag is set you may be able to get an idea of whether the bottleneck happened in the kernel (less likely) or in your client (more likely) by checking for the presence of the informational flags kFSEventStreamEventFlagUserDropped or kFSEventStreamEventFlagKernelDropped.

kFSEventStreamEventFlagUserDropped

The kFSEventStreamEventFlagUserDropped or kFSEventStreamEventFlagKernelDropped flags may be set in addition to the kFSEventStreamEventFlagMustScanSubDirs flag to indicate that a problem occurred in buffering the events (the particular flag set indicates where the problem occurred) and that the client must do a full scan of any directories (and their subdirectories, recursively) being monitored by this stream. If you asked to monitor multiple paths with this stream then you will be notified about all of them. Your code need only check for the kFSEventStreamEventFlagMustScanSubDirs flag; these flags (if present) only provide information to help you diagnose the problem.

kFSEventStreamEventFlagKernelDropped

kFSEventStreamEventFlagEventIdsWrapped

If kFSEventStreamEventFlagEventIdsWrapped is set, it means the 64-bit event ID counter wrapped around. As a result, previously-issued event ID's are no longer valid arguments for the sinceWhen parameter of the FSEventStreamCreate...() functions.

kFSEventStreamEventFlagHistoryDone

Denotes a sentinel event sent to mark the end of the "historical" events sent as a result of specifying a sinceWhen value in the FSEventStreamCreate...() call that created this event stream. (It will not be sent if kFSEventStreamEventIdSinceNow was passed for sinceWhen.) After invoking the client's callback with all the "historical" events that occurred before now, the client's callback will be invoked with an event where the kFSEventStreamEventFlagHistoryDone flag is set. The client should ignore the path supplied in this callback.

kFSEventStreamEventFlagRootChanged

Denotes a special event sent when there is a change to one of the directories along the path to one of the directories you asked to watch. When this flag is set, the event ID is zero and the path corresponds to one of the paths you asked to watch (specifically, the one that changed). The path may no longer exist because it or one of its parents was deleted or renamed. Events with this flag set will only be sent if you passed the flag kFSEventStreamCreateFlagWatchRoot to FSEventStreamCreate...() when you created the stream.

kFSEventStreamEventFlagMount

Denotes a special event sent when a volume is mounted underneath one of the paths being monitored. The path in the event is the path to the newly-mounted volume. You will receive one of these notifications for every volume mount event inside the kernel (independent of DiskArbitration). Beware that a newly-mounted volume could contain an arbitrarily large directory hierarchy. Avoid pitfalls like triggering a recursive scan of a non-local filesystem, which you can detect by checking for the absence of the MNT_LOCAL flag in the f_flags returned by statfs(). Also be aware of the MNT_DONTBROWSE flag that is set for volumes which should not be displayed by user interface elements.

kFSEventStreamEventFlagUnmount

Denotes a special event sent when a volume is unmounted underneath one of the paths being monitored. The path in the event is the path to the directory from which the volume was unmounted. You will receive one of these notifications for every volume unmount event inside the kernel. This is not a substitute for the notifications provided by the DiskArbitration framework; you only get notified after the unmount has occurred. Beware that unmounting a volume could uncover an arbitrarily large directory hierarchy, although OS X never does that.
*/

Notes:

FSEvents explained

The FSEvents API in Mac OS X allows applications to register for notifications of changes to a given directory tree.[1] Whenever the filesystem is changed, the kernel passes notifications via the special device file /dev/fsevents to a userspace process called fseventsd. This process combines multiple changes to a single directory tree that occur within a short period of time, then notifies applications that have registered for changes to the affected directory.

Until Mac OS X 10.7, FSEvents did not “watch” the filesystem, such as Linux’s inotify: the API provided no notifications for changes to individual files. An application was able to register to receive changes to a given directory, and had to determine for itself which file or files were changed.

Mac OS X 10.7 (Lion) added the ability to register for file modification notifications.

  • FSEvents may cause problems pre osx 10.11 see this article for more info to mitigate such problems: stackoverflow

NSWorkspace This seems to be deprecated

  • Apples FSEventFlag overview:
  • FSEventStreamRef
  • This project is a bit unorganized but could serve as a starting point FileSystemEvents
  • This could also possibly be used: NSMetadataQuery
  • This seems to be more reliable than FSEvents for file structures that are big: Kernel Queues
  • Seems like a good FileWatcher class in swift (a bit unorganized) FileWatch
  • KernelQueues wrapper in obj-c: nielsbot
  • another obj-c kernerQueues lib: UKKQueue zip
  • A modern faster version of UKKQueue: VDKQueue
  • another fsevent wrapper in obj-c rastersize/CDEvents
  • This is how you get FSEvents to be work in the current thread: stackoverflow
  • The best FSEvent lib in swift ive come across, but a bit ambiguous and hard to understand: filekit

    Tasks:

  • FileWatching with delegation (but also uses: @objc public func): srphat
  • This article describes how you can have weak self in methods: blog post from xebia.com
  • Make an Element and style it with a red fill, create a button, hock up the logic to live update the element
  • Make a more elaborate test where you live edit a Button from light theme to dark theme and back again
  • Make an even more elaborate test where you reload the css file into the style-manager. (this should gracefully override previous styles right?)
  • ==Research how osx can listen for file changes and alert the app==
  • ==Figure out how to call something on the main thread with FSEvents== See other FSEvent Libs
  • Make a test where if there is a file change the entire UI gets updated
  • Could the LinkResolver be faster when used in StyleCollection, rather than searching through a string
  • Try to make a small app that syncs two folders. Setup que system that performs the alteration on the target folder. It would need to have an include list to pick out which files to sync, like the opposite of ignore. You would also need to use the Table component.