5

Assume a file URL containing /Users/me/a/b. Is there a better method than a naive string replace using NSHomeDirectory() to get the short form ~/a/b?

This is what I'm currently using

.replacingOccurrences(of: NSHomeDirectory(), with: "~", options: .anchored, range: nil)

PS: No NSString casting!

  • What happens if the directory has `/Users/Username/Users/Username`?... you'll end up with `~~` – l'L'l Sep 29 '16 at 09:33
  • Nope. Only first occurrence is replaced. –  Oct 02 '16 at 14:36
  • That likely depends on whether you mean iOS or macOS... it definitely replaces both on the latter. – l'L'l Oct 02 '16 at 14:47
  • Just tested it in a `macOS` playground and it doesnt –  Oct 02 '16 at 14:56
  • Strange... it replaced both for me. http://bl.ocks.org/anonymous/raw/6e36907e3f274b4aeb2b18a16a2627ca – l'L'l Oct 02 '16 at 15:05
  • There is definitely something wrong with your playground. Even if it would replace both occurrences, the last `/foobar` path is still missing in your example. –  Oct 02 '16 at 15:08
  • The last foobar shows... i screen capped before going to another line. http://bl.ocks.org/anonymous/raw/697aa6dbe9d89c40b888084c61e47927 – l'L'l Oct 02 '16 at 15:17

4 Answers4

3

If you are in Sandboxed app then usage of getpwuid function is needed.

extension FileManager {
   /// Returns path to real home directory in Sandboxed application
   public var realHomeDirectory: String? {
      if let home = getpwuid(getuid()).pointee.pw_dir {
         return string(withFileSystemRepresentation: home, length: Int(strlen(home)))
      }
      return nil
   }
}

Example usage:

func configure(url: URL) {
  ...
  var directory = url.path.deletingLastPathComponent
  toolTip = url.path
  if let homeDir = FileManager.default.realHomeDirectory {
     // FYI: `url.path.abbreviatingWithTildeInPath` not working for sandboxed apps.
     let abbreviatedPath = url.path.replacingFirstOccurrence(of: homeDir, with: "~")
     directory = abbreviatedPath.deletingLastPathComponent
     toolTip = abbreviatedPath
  }
  directoryLabel.text = directory
}

More about getpwuid function: How do I get the users home directory in a sandboxed app?


Result of usage in NSView:

enter image description here

Vlad
  • 6,402
  • 1
  • 60
  • 74
0

How about converting to NSString and then abbreviating it with:

var path = url.path as NSString!
var abbrevPath=path?.abbreviatingWithTildeInPath
DDP
  • 2,463
  • 1
  • 26
  • 28
0

NSPathUtilities - (NSString *)stringByAbbreviatingWithTildeInPath; - (NSString *)stringByExpandingTildeInPath;

[blueprintsDict writeToFile: [[NSString stringWithFormat:@"~/MbPatchBlueprints.plist"] stringByExpandingTildeInPath] atomically:YES];
Keith Knauber
  • 752
  • 6
  • 13
0

I noticed this question doesn't have an accepted answer yet, and I ran into the same issue. I tried the NSString methods, but those didn't work in a sandboxed context anyway, and the getpwuid method felt… wrong. So here's a pure Swift solution that's only really hardcoded insofar as it assumes the sandbox root to share the first 3 path components (/, Users, your username) with your actual home directory:

extension URL {
    var pathAbbreviatingWithTilde: String {
        // find home directory path (more difficulty because we're sandboxed, so it's somewhere deep in our actual home dir)
        let sandboxedHomeDir = FileManager.default.homeDirectoryForCurrentUser
        let components = sandboxedHomeDir.pathComponents
        guard components.first == "/" else { return path }
        let homeDir = "/" + components.dropFirst().prefix(2).joined(separator: "/")
        
        // replace home dir in path with tilde for brevity and aesthetics
        guard path.hasPrefix(homeDir) else { return path }
        return "~" + path.dropFirst(homeDir.count)
    }
}
juliand665
  • 2,664
  • 1
  • 16
  • 16