lift max-width limitation
[mdref/mdref] / mdref / Tree.php
1 <?php
2
3 namespace mdref;
4
5 class Tree implements \RecursiveIterator {
6 /**
7 * The repository
8 * @var \mdref\Repo
9 */
10 private $repo;
11
12 /**
13 * List of first level entries
14 * @var array
15 */
16 private $list = array();
17
18 /**
19 * The list iterator
20 * @var array
21 */
22 private $iter;
23
24 /**
25 * @param string $path
26 * @param \mdref\Repo $repo
27 */
28 public function __construct($path, Repo $repo) {
29 if (realpath($path)."/" === $repo->getPath()) {
30 $list = [$path ."/". $repo->getName() .".md"];
31 } elseif (!($list = glob("$path/*.md"))) {
32 $list = glob("$path/*/*.md");
33 }
34 if ($list) {
35 $this->list = array_filter($list, $this->generateFilter($list));
36 usort($this->list, $this->generateSorter());
37 }
38 $this->repo = $repo;
39 }
40
41 /**
42 * @param array $list
43 * @return callable
44 */
45 private function generateFilter(array $list) {
46 return function($v) use($list) {
47 if ($v{0} === ".") {
48 return false;
49 }
50 if (false !== array_search("$v.md", $list, true)) {
51 return false;
52 }
53
54 $pi = pathinfo($v);
55 if (isset($pi["extension"]) && "md" !== $pi["extension"]) {
56 return false;
57 }
58
59 return true;
60 };
61 }
62
63 /**
64 * @return callable
65 */
66 private function generateSorter() {
67 return function($a, $b) {
68 $ab = basename($a, ".md");
69 $bb = basename($b, ".md");
70
71 if ($ab{0} === ":" && $bb{0} === ":") {
72 return strcmp($ab, $bb);
73 } elseif ($ab{0} === ":") {
74 return -1;
75 } elseif ($bb{0} === ":") {
76 return 1;
77 }
78
79 $ad = is_dir(dirname($a)."/$ab");
80 $bd = is_dir(dirname($b)."/$bb");
81
82 if ($ad && $bd) {
83 return strcmp($ab, $bb);
84 } elseif ($ad) {
85 return -1;
86 } elseif ($bd) {
87 return 1;
88 }
89
90 $au = preg_match("/^\p{Lu}/", $ab);
91 $bu = preg_match("/^\p{Lu}/", $bb);
92
93 if ($au && $bu) {
94 return strcmp($ab, $bb);
95 } elseif ($au) {
96 return -1;
97 } elseif ($bu) {
98 return 1;
99 }
100
101 return strcmp($ab, $bb);
102 };
103 }
104
105 /**
106 * Implements \Iterator
107 * @return \mdref\Entry
108 */
109 public function current() {
110 return $this->repo->getEntry($this->repo->hasFile(current($this->iter)));
111 }
112
113 /**
114 * Implements \Iterator
115 */
116 public function next() {
117 next($this->iter);
118 }
119
120 /**
121 * Implements \Iterator
122 * @return int
123 */
124 public function key() {
125 return key($this->iter);
126 }
127
128 /**
129 * Implements \Iterator
130 */
131 public function rewind() {
132 $this->iter = $this->list;
133 reset($this->iter);
134 }
135
136 /**
137 * Implements \Iterator
138 * @return bool
139 */
140 public function valid() {
141 return null !== key($this->iter);
142 }
143
144 /**
145 * Implements \RecursiveIterator
146 * @return bool
147 */
148 public function hasChildren() {
149 return $this->current()->hasIterator();
150 }
151
152 /**
153 * Implements \RecursiveIterator
154 * @return \mdref\Tree
155 */
156 public function getChildren() {
157 return $this->current()->getIterator();
158 }
159 }