sourcecamFantomPlugin::FantomSpace.fan

//
// Copyright (c) 2012, Brian Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   22 Apr 12  Brian Frank  Creation
//

using gfx
using fwt
using camembert

**
** Fantom pod space
**
class FantomSpace : BaseSpace
{
  ** Type of Plugin responsible for this space
  override Str? plugin := FantomPlugin#.pod.name

  override View? view
  override Nav? nav
  override Image icon() { isGroup ? Sys.cur.theme.iconPodGroup : Sys.cur.theme.iconPod }
  FantomIndex index

  ** Whether this is a pod or a pod group
  Bool isGroup
  Widget? slots
  Str podName

  new make(Frame frame, File dir, File? file := null)
      : super(frame, dir, file)
  {
    this.podName = dis
    this.index = FantomPlugin.cur.index
    this.isGroup = ProjectRegistry.projects[dir.normalize.uri]?.params?.containsKey("isGroup") ?: false

    view = View.makeBest(frame, this.file)
    nav = FancyNav(frame, dir, StdItemBuilder(this), FileItem.makeFile(this.file))
    slots = makeSlotNav

    viewParent.content = view ?: FillerPane(Sys.cur.theme.bg)
    navParent.content = nav.list
    slotsParent.content = slots
  }

  PodInfo? curPod() { index.pod(podName, false) }

  TypeInfo? curType()
  {
    pod := curPod
    if (pod == null) return null
      types := pod.types.findAll |t| { t.file == file.name }
    if (types.size == 0) return null
      if (types.size == 1) return types.first
      types.sort |a, b| { a.line <=> b.line }
    curLine := Sys.cur.frame.curView?.curPos?.line ?: 0
    for (i := 1; i<types.size; ++i)
      if (types[i].line > curLine) return types[i-1]
      return types.first
  }

  override Str:Str saveSession()
  {
    ["dir":dir.uri.toStr, "file":file.uri.toStr]
  }

  static Space loadSession(Frame frame, Str:Str props)
  {
    make(frame, props.getOrThrow("dir").toUri.toFile,
      props.get("file")?.toUri?.toFile)
  }

  override Item[] findGotoMatches(Str text)
  {
    Item[] acc := [,]

    /// slots in current type
    if (curType != null)
    {
      curType.slots.each |s|
      {
        if (s.name.startsWith(text))
          acc.add(FantomItem.makeSlot(s, s.name).setIndent(0))
      }
    }

    // match types
    if (!text.isEmpty)
      acc.addAll(index.matchTypes(text).map |t->Item| { FantomItem.makeType(t) })

    // f <file>
    if (text.startsWith("f ") && text.size >= 3)
      acc.addAll(index.matchFiles(text[2..-1]))

    // all matching slots from other types
    acc.addAll(index.matchSlots(text)
      .findAll |s| {s.type.qname != curType?.qname}
      .findAll |s| {s.name.size>0 && text.size>0 && s.name[0] == text[0]}
      .map |s->Item| { FantomItem.makeSlot(s).setIndent(0) })

    return acc
  }

  override Int match(FileItem 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
    if(item.isProject && item.file != dir) return 0
    return 1000 + dir.pathStr.size
  }

  private ItemList? makeSlotNav()
  {
    if (file.ext != "fan") return null
    pod := index.pod(this.podName, false)
    if (pod == null) return null

    types := pod.types.findAll |t| { return t.file == file.name }

    if (types.isEmpty) return null

    items := Item[,]
    types.sort |a, b| { a.line <=> b.line }
    types.each |t|
    {
      items.add(FantomItem.makeType(t, t.name))
      slots := t.slots.dup.sort |a, b| { a.name <=> b.name }
      slots.each |s|
      {
        items.add(FantomItem.makeSlot(s, s.name))
      }
    }
    return ItemList(frame, items, 175)
  }

  ** Go to the given item. (in Editor & Nav)
  override Void goto(FileItem? item)
  {
    super.goto(item)

    // Update slot nav ?
    newSlots := makeSlotNav()
    slotsParent.content = newSlots
    slotsUpdated(newSlots == null || newSlots.items.isEmpty)
  }
}