ZyX_I avatar ZyX_I committed f8e00c3

@/os: Added os.path.relpath function
Made abspath also work for paths like a/b/c where a/ does not exist
Made os.path.normpath also simplify its argument

Comments (0)

Files changed (6)

              Matching is done case-sensitively by default.
     Completer: ignored.
 
-path {pathspec}                                                   *FWC-c-path*
+path {pathspec}                                      *FWC-c-path* *FWC-f-path*
     Checker: checks whether current argument is a path matching given 
              specification.
     Filter: before checking expands path without globbing (uses |expand()| 
         Returns an absolute path.
 os.path.realpath :: path + FS -> path              *frawor-r-os.path.realpath*
         Returns an absolute path with all symbolic links resolved.
+os.path.relpath  :: path[, path] -> path              *frawor-os.path.relpath*
+        Transforms its first argument so that it will be a path, relative to 
+        the path given in the second argument (default: current directory). 
+        Returns transformed version of path or 0 if it cannot be constructed 
+        (for example, if paths are on different drives on windows).
 os.path.normpath :: path -> path                   *frawor-r-os.path.normpath*
-        Normalize path by removing duplicate path separators.
+        Normalize path by removing duplicate path separators and simplifying 
+        it (see |simplify()|).
 os.path.basename :: path -> component              *frawor-r-os.path.basename*
         Returns the final component of a path.
 os.path.dirname :: path -> path                     *frawor-r-os.path.dirname*
                                   |frawor-f-addresource|.
 ==============================================================================
 8. Changelog                                                *frawor-changelog*
+Only API changes are listed here. See commit log in order to get other 
+changes.
 
 @/mappings:
     0.1: Added possibility to specify dictionaries in `strfunc' and `func' 
          keys.
 @/table:
-    0.1: Posted strdisplaywidth function
+    0.1: Posted |frawor-r-strdisplaywidth|
 @/fwc:
-    0.1: (intfuncs-0.1) Added `idof' checker
-    0.2: (intfuncs-0.2) Made `path' filter expand argument
+    0.1: (intfuncs-0.1) Added |FWC-c-idof|
+    0.2: (intfuncs-0.2) Made |FWC-f-path| filter expand argument
+@/os:
+    0.1: Added |frawor-r-os.path.relpath|
+         Made |frawor-r-os.path.normpath| also simplify its argument
 
 vim: ft=help:tw=78

plugin/frawor/os.vim

 "▶1 Header
 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@/resources': '0.0'}, 1)
+execute frawor#Setup('0.1', {'@/resources': '0.0'}, 1)
 "▶1 os resource
 let s:os={}
 "▶2 os.fullname
 let s:os.path={}
 "▶3 os.path.abspath   :: path + FS → path
 function s:os.path.abspath(path)
-    let path=fnamemodify(a:path, ':p')
-    " Purge trailing path separator
-    return ((isdirectory(path) && len(path)>1)?(path[:-2]):(path))
+    let components=s:os.path.split(a:path)
+    if components[0] is# '.'
+        let components[:0]=[fnamemodify('.', ':p')]
+        if len(components[0])>1
+            let components[0]=components[0][:-2]
+        endif
+    endif
+    return s:os.path.join(components)
 endfunction
 "▶3 os.path.realpath  :: path + FS → path
 function s:os.path.realpath(path)
     return resolve(s:os.path.abspath(a:path))
 endfunction
+"▶3 os.path.relpath   :: path[, curdir] → path
+function s:os.path.relpath(path, ...)
+    let components=s:os.path.split(s:os.path.abspath(
+                \                                   s:os.path.normpath(a:path)))
+    let tcomponents=s:os.path.split(s:os.path.abspath(
+                \                               (a:0)?(s:os.path.normpath(a:1)):
+                \                                     ('.')))
+    if components[0] isnot# tcomponents[0]
+        " This is valid for windows: you can't construct a relative path if 
+        " directory to which path should be relative is on another drive
+        return 0
+    endif
+    let l=min([len(components), len(tcomponents)])
+    let i=1
+    while i<l && components[i] is# tcomponents[i]
+        let i+=1
+    endwhile
+    return s:os.path.join(repeat([".."], len(tcomponents)-i)+components[(i):])
+endfunction
 "▶3 os.path.basename  :: path → component
 function s:os.path.basename(path)
     return fnamemodify(a:path, ':t')
 endfunction
 "▶3 os.path.normpath  :: path → path
 function s:os.path.normpath(path)
-    return s:os.path.join(s:os.path.split(a:path))
+    return simplify(s:os.path.join(s:os.path.split(a:path)))
 endfunction
 "▶3 os.path.samefile  :: path, path + FS → Bool
 function s:os.path.samefile(path1, path2)
 Basename of a/b: b
 Dirname of a/b: a
 a/b/c components: ., a, b, c
+a/b/c relative to a: b\c
+a/b/c relative to .: a\b\c
+a/b/c relative to d: ..\a\b\c
 : mkdir
 a:     0
 a/b:   0

Binary file modified.

test/rtp/plugin/os.vim

 call WriteFile('Basename of a/b: '.os.path.basename(ab))
 call WriteFile('Dirname of a/b: '.os.path.dirname(ab))
 call WriteFile('a/b/c components: '.join(os.path.split(abc), ', '))
+call WriteFile('a/b/c relative to a: '.os.path.relpath(abc, a))
+call WriteFile('a/b/c relative to .: '.os.path.relpath(abc))
+call WriteFile('a/b/c relative to d: '.os.path.relpath(abc, 'd'))
 
 W: mkdir
 call os.mkdir(abc)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.