Commits

Thibaut Colar committed 2c5dea3

Full support for pod groups : pod groups and pods are seen directly in file/pod navs and can be accessed at each level.
Also clicking a group / pod item in either nav view directly opens the proper pod space

  • Participants
  • Parent commits bfd12d4

Comments (0)

Files changed (13)

File src/brie/fan/Frame.fan

     // current always trumps others
     if (curSpace.match(item) > 0) return curSpace
 
-      // find best match
+    // find best match
     Space? bestSpace := null
     Int bestPriority := 0
     this.spaces.each |s|
     pod := sys.index.podForFile(file)
     if (pod != null) return PodSpace(sys, pod.name, pod.srcDir)
 
+    group := sys.index.groupForFile(file)
+    if (group != null) return PodSpace(sys, group.name, group.srcDir)
+
     dir := file.isDir ? file : file.parent
     return FileSpace(sys, dir)
   }

File src/brie/fan/command/Commands.fan

   override const Str name := "Edit config"
   override Void invoke(Event event)
   {
-    frame.goto(Item.makeFile(Options.file))
+    frame.goto(Item(Options.file))
   }
   new make(|This| f) {f(this)}
 }

File src/brie/fan/index/Index.fan

   ** List all pods found
   PodInfo[] pods() { ((Unsafe)cache.send(Msg("pods")).get(timeout)).val }
 
+  ** List all groups found
+  PodGroup[] groups() { ((Unsafe)cache.send(Msg("groups")).get(timeout)).val }
+
   ** Find given pod
   PodInfo? pod(Str name, Bool checked := true)
   {
     cache.send(Msg("podForFile", file)).get(timeout)
   }
 
+  ** Find given pod
+  PodGroup? groupForFile(File file)
+  {
+    cache.send(Msg("groupForFile", file)).get(timeout)
+  }
+
   ** Rebuild the entire index asynchronously
   Void reindexAll()
   {
     cache.send(Msg("matchFiles", pattern, kind)).get(timeout)->val
   }
 
+  ** Whether this is the srcDir(root) of a pod
+  ** Returns the matching pod or null if no match
+  PodInfo? isPodDir(File f)
+  {
+    return pods.eachWhile |p|
+    {
+      if(p.srcDir.normalize.uri == f.normalize.uri)
+        return p
+      return null
+    }
+  }
+
+  ** Whether this is the srcDir(root) of a group
+  ** Returns the matching group or null if no match
+  PodGroup? isGroupDir(File f)
+  {
+    return groups.eachWhile |g|
+    {
+      if(g.srcDir.normalize.uri == f.normalize.uri)
+        return g
+      return null
+    }
+  }
+
+
 //////////////////////////////////////////////////////////////////////////
 // Cache Actor
 //////////////////////////////////////////////////////////////////////////
 
     id := msg.id
     if (id === "pods")        return Unsafe(c.listPods)
+    if (id === "groups")      return Unsafe(c.listGroups)
     if (id === "pod")         return c.pod(msg.a)
     if (id === "podForFile")  return c.podForFile(msg.a)
+    if (id === "groupForFile")  return c.groupForFile(msg.a)
     if (id === "matchTypes")  return Unsafe(c.matchTypes(msg.a, msg.b))
     if (id === "matchSlots")  return Unsafe(c.matchSlots(msg.a, msg.b, msg.c))
     if (id === "matchPods")  return Unsafe(c.matchPods(msg.a, msg.b))

File src/brie/fan/index/IndexCache.fan

 
   PodInfo[] listPods() { pods.vals.sort }
 
+  PodGroup[] listGroups() { groups.vals.sort |g1, g2| {g1.name <=> g2.name}}
+
   PodInfo? pod(Str name) { pods[name] }
 
   PodInfo? podForFile(File file)
     }
   }
 
+  PodGroup? groupForFile(File file)
+  {
+    file = file.normalize
+    return groups.find |group|
+    {
+      echo("$file.pathStr  ->  $group.srcDir.pathStr")
+      return file.pathStr.startsWith(group.srcDir.pathStr)
+    }
+  }
+
   Obj? addPodSrc(Str name, File srcDir, File[] srcFiles)
   {
     cur := pods[name] ?: PodInfo(name, null, TypeInfo[,], null, File#.emptyList, null)

File src/brie/fan/index/IndexModel.fan

     this.types      = types
     this.srcDir     = srcDir
     this.srcFiles   = srcFiles
-    this.group      = group
+    this.groupRef.val= group
     types.each |t| { t.podRef.val = this; }
   }
 
   const TypeInfo[] types
   const File? srcDir
   const File[] srcFiles
-  const PodGroup? group
+  PodGroup? group() { groupRef.val }
+  internal const AtomicRef groupRef := AtomicRef()
 }
 
 const class TypeInfo

File src/brie/fan/space/FileSpace.fan

   override Int match(Item item)
   {
     if (!FileUtil.contains(this.dir, item.file)) return 0
+    // if group or pod we don't want to open them here but in a pod space
     if (item.pod != null) return 0
+    if (item.group != null) return 0
     return this.dir.path.size
   }
 

File src/brie/fan/space/HomeSpace.fan

 
   override Widget onLoad(Frame frame)
   {
-    podGroups := ItemList[,]
+    podRoots := ItemList[,]
     pods := sys.index.pods.dup
+    groups := sys.index.groups.dup
     sys.index.srcDirs.each |indexDir|
     {
       items := Item[,]
       items.add(Item(indexDir) { it.dis = FileUtil.pathDis(indexDir) })
-      podsInDir := pods.findAll |p|
-      {
-        p.srcDir != null && FileUtil.contains(indexDir, p.srcDir)
-      }
-      podsInDir.each |p|
-      {
-        pods.removeSame(p)
-        items.add(Item(p))
-      }
-      podGroups.add(ItemList(frame, items))
+
+      addItems(indexDir, groups, pods, items)
+
+      podRoots.add(ItemList(frame, items))
     }
 
     grid := GridPane
     {
-      numCols = podGroups.size
+      numCols = podRoots.size
       valignCells = Valign.fill
       expandRow = 0
     }
-    podGroups.each |g| { grid.add(g) }
+    podRoots.each |g| { grid.add(g) }
     return InsetPane(0, 5, 5, 5) { grid, }
   }
+  Void addPod(PodInfo p, Item[] items)
+  {
+  }
+
+  Void addItems(File indexDir, PodGroup[] groups, PodInfo[] pods, Item[] items, Str curGroup := "", Int ind := 0)
+  {
+      groupsInDir := groups.findAll |g|
+      {
+        return (g.parent?.name ?: "") == curGroup
+            && FileUtil.contains(indexDir, g.srcDir)
+      }
+      podsInDir := pods.findAll |p|
+      {
+        return (p.group?.name ?: "") == curGroup
+            && p.srcDir != null
+            && FileUtil.contains(indexDir, p.srcDir)
+      }
+      // pod groups
+      groupsInDir.each |g|
+      {
+        groups.removeSame(g)
+        items.add(Item(g) {indent = ind})
+        // Now recurse for what is in this group
+        addItems(g.srcDir, groups, pods, items, g.name, ind + 1)
+      }
+      // single pods
+      podsInDir.each |p|
+      {
+        pods.removeSame(p)
+        items.add(Item(p) {indent = ind})
+      }
+  }
 }
 

File src/brie/fan/space/PodSpace.fan

     if (!dir.isDir) throw Err("Not a dir: $dir")
       this.name = name
     this.dir  = dir.normalize
-    this.file = file ?: FileUtil.findBuildPod(dir, dir)
+    this.isGroup = sys.index.isGroupDir(dir) != null
+    this.file = isGroup ?
+                  (file ?: FileUtil.findBuildGroup(dir))
+                : (file ?: FileUtil.findBuildPod(dir, dir))
     Regex[] r := Regex[,]
     try
     {
   ** Patterns of files to hide
   const Regex[] hideFiles
 
+  ** Whether this is a pod or a pod group
+  const Bool isGroup
+
   override Str dis() { name }
 
-  override Image icon() { sys.theme.iconPod }
+  override Image icon() { isGroup ? sys.theme.iconPodGroup : sys.theme.iconPod }
 
   override File? curFile() { file }
 
 
   override Int match(Item item)
   {
+    // add 1000 so always preferred over filespace
+    // use length so the "Deepest" (sub)pod matches first
     if (!FileUtil.contains(this.dir, item.file)) return 0
-      return 1000
+    // Pods from groups should open in own space
+    if(isGroup && item.pod != null) return 0
+    return 1000 + dir.pathStr.size
   }
 
   override This goto(Item item)
 
   override Widget onLoad(Frame frame)
   {
-    frame.history.push(this, Item.makeFile(file))
+    frame.history.push(this, Item(file))
     return EdgePane
     {
       left = EdgePane
 
   private Widget makeFileNav(Frame frame)
   {
-    // get all the files
-    files := File[,]
-    dir.walk |f|
+    items := [Item(dir)]
+    findItems(dir, items)
+    return ItemList(frame, items)
+  }
+
+  private Void findItems(File dir, Item[] results, Str path := "")
+  {
+    dir.listFiles.sort |a, b| {a.name  <=> b.name}.each |f|
     {
       hidden := hideFiles.eachWhile |Regex r -> Bool?| {
         r.matches(f.uri.toStr) ? true : null} ?: false
-      if (!f.isDir && !hidden)
-        files.add(f)
+      if (! hidden)
+      {
+        results.add(Item(f) { it.indent = path.isEmpty ? 0 : 1 })
+      }
     }
 
-    // organize by dir
-    byDir := File:File[][:]
-    files.each |f|
+    dir.listDirs.sort |a, b| {a.name  <=> b.name}.each |f|
     {
-      bucket := byDir.getOrAdd(f.parent) { File[,] }
-      bucket.add(f)
+      hidden := hideFiles.eachWhile |Regex r -> Bool?| {
+        r.matches(f.uri.toStr) ? true : null} ?: false
+      if (! hidden)
+      {
+        results.add(Item(f) { it.dis = "${path}$f.name/"})
+        // Not recursing in pods or pod groups
+        if(sys.index.isPodDir(f)==null && sys.index.isGroupDir(f) == null)
+          findItems(f, results, "${path}$f.name/")
+      }
     }
-
-    // now map to items
-    items := Item[,]
-    items.add(Item(dir) { it.dis = FileUtil.pathDis(dir); it.header=true })
-    byDir.keys.sort.each |d|
-    {
-      indent := 0
-      if (d.path.size != this.dir.path.size)
-      {
-        dirDis := d.path[this.dir.path.size..-1].join("/") + "/"
-        items.add(Item(d) { it.dis = dirDis; } )
-        indent = 1
-      }
-      bucket := byDir[d].sort |a,b| { a.name <=> b.name }
-      bucket.each |f| { items.add(Item(f) { it.indent = indent }) }
-    }
-
-    return ItemList(frame, items)
   }
 
   private Widget? makeSlotNav(Frame frame)

File src/brie/fan/util/Theme.fan

   const Image iconDirty     := Image(`fan://camembert/res/dirty.png`)
   const Image iconNotDirty  := Image(`fan://camembert/res/notDirty.png`)
   const Image iconPod       := Image(`fan://icons/x16/database.png`)
+  const Image iconPodGroup  := Image(`fan://camembert/res/podGroup.png`)
   const Image iconType      := Image(`fan://camembert/res/type.png`)
   const Image iconField     := Image(`fan://camembert/res/field.png`)
   const Image iconMethod    := Image(`fan://camembert/res/method.png`)

File src/brie/fan/view/ImageView.fan

   new make(Frame frame, File file) : super(frame, file)
   {
     sys := Service.find(Sys#) as Sys
-    image = Image.makeFile(file)
+    image = Image(file)
     details := EdgePane
     {
       it.top = InsetPane(6)

File src/brie/fan/widget/Item.fan

     this.dis  = file.name + (file.isDir ? "/" : "")
     this.icon = Theme.fileToIcon(file)
     this.file = file
+    // check if this is a pod / group root first
+    if(file.isDir)
+    {
+      g := sys.index.isGroupDir(file)
+      p := sys.index.isPodDir(file)
+      if(g != null)
+      {
+        this.dis  = g.name
+        this.icon = sys.theme.iconPodGroup
+        this.file = g.srcDir
+      }
+      else if(p != null)
+      {
+        this.dis  = p.name
+        this.icon = sys.theme.iconPod
+        this.file = FileUtil.findBuildPod(p.srcDir, p.srcDir)
+        this.pod  = p
+      }
+    }
     if (f != null) f(this)
   }
 
     if (f != null) f(this)
   }
 
+  new makeGroup(PodGroup g, |This|? f := null)
+  {
+    this.dis  = g.name
+    this.icon = sys.theme.iconPodGroup
+    this.file = g.srcDir
+    this.group = g.name
+    if (f != null) f(this)
+  }
+
   new makeType(TypeInfo t, |This|? f := null)
   {
     this.dis  = t.qname
 
   const Int indent
 
+  const Str? group
+
   override Str toStr() { dis }
 
   Str debug() {"$dis $file $pod $type $slot"}

File src/brie/res/podGroup.png

Added
New image

File src/brie/todo.txt

 rename file
 duplicate file
 
+line numbering needs to startat 1 not zero (bocce)
+
 replace in file
 replace in space