sortri.ml (5143B)
1 (* Unison file synchronizer: src/sortri.ml *) 2 (* Copyright 1999-2020, Benjamin C. Pierce 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 *) 17 18 19 open Common 20 21 let dbgsort = Util.debug "sort" 22 23 (* Preferences *) 24 25 let bysize = 26 Prefs.createBool "sortbysize" false 27 ~category:(`Advanced `Syncprocess) 28 "list changed files by size, not name" 29 ("When this flag is set, the user interface will list changed files " 30 ^ "by size (smallest first) rather than by name. This is useful, for " 31 ^ "example, for synchronizing over slow links, since it puts very " 32 ^ "large files at the end of the list where they will not prevent " 33 ^ "smaller files from being transferred quickly.\n\n" 34 ^ "This preference (as well as the other sorting flags, but not the " 35 ^ "sorting preferences that require patterns as arguments) can be " 36 ^ "set interactively and temporarily using the 'Sort' menu in the " 37 ^ "graphical and text user interfaces.") 38 39 let newfirst = 40 Prefs.createBool "sortnewfirst" false 41 ~category:(`Advanced `Syncprocess) 42 "list new before changed files" 43 ("When this flag is set, the user interface will list newly created " 44 ^ "files before all others. This is useful, for example, for checking " 45 ^ "that newly created files are not `junk', i.e., ones that should be " 46 ^ "ignored or deleted rather than synchronized.") 47 48 let sortfirst = Pred.create "sortfirst" 49 ~category:(`Advanced `Syncprocess) 50 ("Each argument to \\texttt{sortfirst} is a pattern \\ARG{pathspec}, " 51 ^ "which describes a set of paths. " 52 ^ "Files matching any of these patterns will be listed first in the " 53 ^ "user interface. " 54 ^ "The syntax of \\ARG{pathspec} is " 55 ^ "described in \\sectionref{pathspec}{Path Specification}.") 56 57 let sortlast = Pred.create "sortlast" 58 ~category:(`Advanced `Syncprocess) 59 ("Similar to \\verb|sortfirst|, except that files matching one of these " 60 ^ "patterns will be listed at the very end.") 61 62 type savedPrefs = {nf:bool; bs:bool; sf:string list; sl:string list} 63 let savedPrefs = ref(None) 64 65 let saveSortingPrefs () = 66 if !savedPrefs = None then 67 savedPrefs := Some { 68 sf = Pred.extern sortfirst; 69 sl = Pred.extern sortlast; 70 bs = Prefs.read bysize; 71 nf = Prefs.read newfirst } 72 73 let restoreDefaultSettings () = 74 match !savedPrefs with 75 None -> () 76 | Some {nf=nf; bs=bs; sf=sf; sl=sl} -> 77 Prefs.set newfirst nf; 78 Prefs.set bysize bs; 79 Pred.intern sortfirst sf; 80 Pred.intern sortlast sl 81 82 let zeroSortingPrefs () = 83 Prefs.set newfirst false; 84 Prefs.set bysize false; 85 Pred.intern sortfirst []; 86 Pred.intern sortlast [] 87 88 (* ------------------- *) 89 90 let sortByName () = 91 saveSortingPrefs(); 92 zeroSortingPrefs() 93 94 let sortBySize () = 95 saveSortingPrefs(); 96 zeroSortingPrefs(); 97 Prefs.set bysize true 98 99 let sortNewFirst () = 100 saveSortingPrefs(); 101 Prefs.set newfirst (not (Prefs.read newfirst)) 102 103 (* ---------------------------------------------------------------------- *) 104 (* Main sorting functions *) 105 106 let shouldSortFirst ri = 107 Pred.test sortfirst (Path.toString ri.path1) 108 let shouldSortLast ri = 109 Pred.test sortlast (Path.toString ri.path1) 110 111 let newItem ri = 112 let newItem1 ri = 113 match ri.replicas with 114 Different diff -> diff.rc1.status = `Created 115 | _ -> false in 116 let newItem2 ri = 117 match ri.replicas with 118 Different diff -> diff.rc2.status = `Created 119 | _ -> false 120 in newItem1 ri || newItem2 ri 121 122 (* Should these go somewhere else? *) 123 let rec combineCmp = function 124 [] -> 0 125 | c::cs -> if c<>0 then c else combineCmp cs 126 let invertCmp c = c * -1 127 128 let compareReconItems () = 129 let newfirst = Prefs.read newfirst in 130 fun ri1 ri2 -> 131 let pred p = 132 let b1 = p ri1 in let b2 = p ri2 in 133 if b1 && b2 then 0 else if b1 then -1 else if b2 then 1 else 0 in 134 let cmp = 135 combineCmp [ 136 pred problematic; 137 pred partiallyProblematic; 138 pred shouldSortFirst; 139 invertCmp (pred shouldSortLast); 140 if newfirst then pred newItem else 0; 141 (if Prefs.read bysize then 142 let l1 = Common.riLength ri1 in 143 let l2 = Common.riLength ri2 in 144 if l1<l2 then -1 else if l2<l1 then 1 else 0 145 else 0); 146 (compare (Path.toString ri1.path1) (Path.toString ri2.path1)) 147 ] in 148 dbgsort (fun() -> Util.msg "%s <= %s --> %d\n" 149 (Path.toString ri1.path1) (Path.toString ri2.path1) cmp); 150 cmp 151 152 let sortReconItems items = Safelist.stable_sort (compareReconItems()) items