diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt
index 7779e26f4b2d1392414573ed4e7bc300d42b4a52..b722544e707394d141977abece3ba21a123d9492 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt
@@ -3,40 +3,46 @@ package de.kuschku.quasseldroid_ng.ui.chat
 import android.arch.lifecycle.LifecycleOwner
 import android.arch.lifecycle.LiveData
 import android.arch.lifecycle.Observer
+import android.graphics.drawable.Drawable
+import android.support.v4.graphics.drawable.DrawableCompat
 import android.support.v7.util.DiffUtil
 import android.support.v7.widget.RecyclerView
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.widget.ImageView
 import android.widget.TextView
 import butterknife.BindView
 import butterknife.ButterKnife
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 import de.kuschku.quasseldroid_ng.R
+import de.kuschku.quasseldroid_ng.ui.chat.NickListAdapter.Companion.VIEWTYPE_AWAY
+import de.kuschku.quasseldroid_ng.ui.chat.buffers.BufferListAdapter
+import de.kuschku.quasseldroid_ng.util.helper.getCompatDrawable
+import de.kuschku.quasseldroid_ng.util.helper.styledAttributes
 import de.kuschku.quasseldroid_ng.util.helper.visibleIf
-import de.kuschku.quasseldroid_ng.util.irc.IrcCaseMappers
 
 class AutoCompleteAdapter(
   lifecycleOwner: LifecycleOwner,
-  liveData: LiveData<List<NickListAdapter.IrcUserItem>?>,
+  liveData: LiveData<List<AutoCompleteItem>?>,
   runInBackground: (() -> Unit) -> Any,
   runOnUiThread: (Runnable) -> Any,
   private val clickListener: ((String) -> Unit)? = null
-) : RecyclerView.Adapter<AutoCompleteAdapter.NickViewHolder>() {
-  var data = mutableListOf<NickListAdapter.IrcUserItem>()
+) : RecyclerView.Adapter<AutoCompleteAdapter.AutoCompleteViewHolder>() {
+  var data = mutableListOf<AutoCompleteItem>()
 
   init {
     liveData.observe(
-      lifecycleOwner, Observer { it: List<NickListAdapter.IrcUserItem>? ->
+      lifecycleOwner, Observer { it: List<AutoCompleteItem>? ->
       runInBackground {
         val list = it ?: emptyList()
-        val old: List<NickListAdapter.IrcUserItem> = data
-        val new: List<NickListAdapter.IrcUserItem> = list
-          .sortedBy { IrcCaseMappers[it.networkCasemapping].toLowerCase(it.nick) }
-          .sortedBy { it.lowestMode }
+        val old: List<AutoCompleteItem> = data
+        val new: List<AutoCompleteItem> = list
         val result = DiffUtil.calculateDiff(
           object : DiffUtil.Callback() {
             override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
-              old[oldItemPosition].nick == new[newItemPosition].nick
+              old[oldItemPosition].name == new[newItemPosition].name
 
             override fun getOldListSize() = old.size
             override fun getNewListSize() = new.size
@@ -56,66 +62,172 @@ class AutoCompleteAdapter(
     )
   }
 
-  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = NickViewHolder(
-    LayoutInflater.from(parent.context).inflate(
-      when (viewType) {
-        VIEWTYPE_AWAY -> R.layout.widget_nick_away
-        else          -> R.layout.widget_nick
-      }, parent, false
-    ),
-    clickListener = clickListener
-  )
+  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) {
+    VIEWTYPE_CHANNEL                         -> AutoCompleteViewHolder.ChannelViewHolder(
+      LayoutInflater.from(parent.context)
+        .inflate(R.layout.widget_buffer, parent, false),
+      clickListener = clickListener
+    )
+    VIEWTYPE_NICK_ACTIVE, VIEWTYPE_NICK_AWAY -> AutoCompleteViewHolder.NickViewHolder(
+      LayoutInflater.from(parent.context).inflate(
+        when (viewType) {
+          VIEWTYPE_AWAY -> R.layout.widget_nick_away
+          else          -> R.layout.widget_nick
+        }, parent, false
+      ),
+      clickListener = clickListener
+    )
+    else                                     -> throw IllegalArgumentException(
+      "Invoked with wrong item type"
+    )
+  }
 
-  override fun onBindViewHolder(holder: NickViewHolder, position: Int) = holder.bind(data[position])
+  override fun onBindViewHolder(holder: AutoCompleteViewHolder, position: Int) =
+    holder.bind(data[position])
 
   override fun getItemCount() = data.size
 
-  override fun getItemViewType(position: Int) = if (data[position].away) {
-    VIEWTYPE_AWAY
-  } else {
-    VIEWTYPE_ACTIVE
+  override fun getItemViewType(position: Int) = data[position].let { it ->
+    when {
+      it is AutoCompleteItem.ChannelItem         -> VIEWTYPE_CHANNEL
+      it is AutoCompleteItem.UserItem && it.away -> VIEWTYPE_NICK_AWAY
+      else                                       -> VIEWTYPE_NICK_ACTIVE
+    }
   }
 
-  class NickViewHolder(
-    itemView: View,
-    private val clickListener: ((String) -> Unit)? = null
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.modesContainer)
-    lateinit var modesContainer: View
+  sealed class AutoCompleteItem(open val name: String) : Comparable<AutoCompleteItem> {
+    override fun compareTo(other: AutoCompleteItem): Int {
+      return when {
+        this is AutoCompleteItem.UserItem &&
+        other is AutoCompleteItem.ChannelItem -> -1
+        this is AutoCompleteItem.ChannelItem &&
+        other is AutoCompleteItem.UserItem    -> 1
+        else                                  -> this.name.compareTo(other.name)
+      }
+    }
+
+    data class UserItem(
+      val nick: String,
+      val modes: String,
+      val lowestMode: Int,
+      val realname: CharSequence,
+      val away: Boolean,
+      val networkCasemapping: String
+    ) : AutoCompleteItem(nick)
+
+    data class ChannelItem(
+      val info: BufferInfo,
+      val network: INetwork.NetworkInfo,
+      val bufferStatus: BufferListAdapter.BufferStatus,
+      val description: CharSequence
+    ) : AutoCompleteItem(info.bufferName ?: "")
+  }
+
+  sealed class AutoCompleteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+    fun bind(data: AutoCompleteItem) = when {
+      data is AutoCompleteItem.UserItem && this is NickViewHolder       -> this.bindImpl(data)
+      data is AutoCompleteItem.ChannelItem && this is ChannelViewHolder -> this.bindImpl(data)
+      else                                                              -> throw IllegalArgumentException(
+        "Invoked with wrong item type"
+      )
+    }
+
+    class NickViewHolder(
+      itemView: View,
+      private val clickListener: ((String) -> Unit)? = null
+    ) : AutoCompleteViewHolder(itemView) {
+      @BindView(R.id.modesContainer)
+      lateinit var modesContainer: View
+
+      @BindView(R.id.modes)
+      lateinit var modes: TextView
+
+      @BindView(R.id.nick)
+      lateinit var nick: TextView
 
-    @BindView(R.id.modes)
-    lateinit var modes: TextView
+      @BindView(R.id.realname)
+      lateinit var realname: TextView
 
-    @BindView(R.id.nick)
-    lateinit var nick: TextView
+      var value: String? = null
 
-    @BindView(R.id.realname)
-    lateinit var realname: TextView
+      init {
+        ButterKnife.bind(this, itemView)
+        itemView.setOnClickListener {
+          val value = value
+          if (value != null)
+            clickListener?.invoke(value)
+        }
+      }
+
+      fun bindImpl(data: AutoCompleteItem.UserItem) {
+        value = data.name
 
-    var user: String? = null
+        nick.text = data.nick
+        modes.text = data.modes
+        realname.text = data.realname
 
-    init {
-      ButterKnife.bind(this, itemView)
-      itemView.setOnClickListener {
-        val nick = user
-        if (nick != null)
-          clickListener?.invoke(nick)
+        modes.visibleIf(data.modes.isNotBlank())
       }
     }
 
-    fun bind(data: NickListAdapter.IrcUserItem) {
-      user = data.nick
+    class ChannelViewHolder(
+      itemView: View,
+      private val clickListener: ((String) -> Unit)? = null
+    ) : AutoCompleteViewHolder(itemView) {
+      @BindView(R.id.status)
+      lateinit var status: ImageView
+
+      @BindView(R.id.name)
+      lateinit var name: TextView
+
+      @BindView(R.id.description)
+      lateinit var description: TextView
+
+      var value: String? = null
+
+      private val online: Drawable
+      private val offline: Drawable
+
+      init {
+        ButterKnife.bind(this, itemView)
+        itemView.setOnClickListener {
+          val value = value
+          if (value != null)
+            clickListener?.invoke(value)
+        }
+
+        online = itemView.context.getCompatDrawable(R.drawable.ic_status_channel).mutate()
+        offline = itemView.context.getCompatDrawable(R.drawable.ic_status_channel_offline).mutate()
+
+        itemView.context.theme.styledAttributes(
+          R.attr.colorAccent, R.attr.colorAway
+        ) {
+          DrawableCompat.setTint(online, getColor(0, 0))
+          DrawableCompat.setTint(offline, getColor(1, 0))
+        }
+      }
 
-      nick.text = data.nick
-      modes.text = data.modes
-      realname.text = data.realname
+      fun bindImpl(data: AutoCompleteItem.ChannelItem) {
+        value = data.name
 
-      modes.visibleIf(data.modes.isNotBlank())
+        name.text = data.info.bufferName
+        description.text = data.description
+
+        description.visibleIf(data.description.isNotBlank())
+
+        status.setImageDrawable(
+          when (data.bufferStatus) {
+            BufferListAdapter.BufferStatus.ONLINE -> online
+            else                                  -> offline
+          }
+        )
+      }
     }
   }
 
   companion object {
-    val VIEWTYPE_ACTIVE = 0
-    val VIEWTYPE_AWAY = 1
+    val VIEWTYPE_CHANNEL = 0
+    val VIEWTYPE_NICK_ACTIVE = 1
+    val VIEWTYPE_NICK_AWAY = 2
   }
 }
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
index 3ee817471c44c8fb24fdc68d4264f1ed265c331f..732cc3f1319ed662c6ed878cc944cf38894884b9 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
@@ -45,7 +45,6 @@ import de.kuschku.quasseldroid_ng.util.helper.*
 import de.kuschku.quasseldroid_ng.util.service.ServiceBoundActivity
 import de.kuschku.quasseldroid_ng.util.ui.MaterialContentLoadingProgressBar
 import io.reactivex.subjects.BehaviorSubject
-import java.util.concurrent.TimeUnit
 
 class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenceChangeListener,
                      ActionMenuView.OnMenuItemClickListener {
@@ -116,8 +115,9 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
 
   private val lastWord = BehaviorSubject.createDefault("")
   private val textWatcher = object : TextWatcher {
-    override fun afterTextChanged(s: Editable?) =
+    override fun afterTextChanged(s: Editable?) {
       lastWord.onNext(s?.lastWord(chatline.selectionStart, onlyBeforeCursor = true).toString())
+    }
 
     override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
     override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
@@ -142,6 +142,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
 
     viewModel = ViewModelProviders.of(this)[QuasselViewModel::class.java]
     viewModel.setBackend(this.backend)
+    viewModel.lastWord.value = lastWord
     backlogSettings = Settings.backlog(this)
 
     inputEditor = InputEditor(chatline)
@@ -223,21 +224,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
 
     val autocompleteAdapter = AutoCompleteAdapter(
       this,
-      viewModel.nickData.switchMapRx { nicks ->
-        lastWord
-          .map { if (it.length >= 3) it else "" }
-          .distinctUntilChanged()
-          .debounce(300, TimeUnit.MILLISECONDS)
-          .map { input ->
-            if (input.isEmpty()) {
-              emptyList()
-            } else {
-              nicks.filter {
-                it.nick.contains(input, ignoreCase = true)
-              }.sortedBy(NickListAdapter.IrcUserItem::nick)
-            }
-          }
-      },
+      viewModel.autoCompleteData,
       handler::post,
       ::runOnUiThread,
       inputEditor::autoComplete
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt
index 60c584f2cbffde72d87aa242289b61482b7623b9..2938374049fa7e6377a8c27fb4bdd820a84bf389 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt
@@ -16,6 +16,7 @@ import de.kuschku.libquassel.session.ISession
 import de.kuschku.libquassel.session.SessionManager
 import de.kuschku.libquassel.util.and
 import de.kuschku.libquassel.util.hasFlag
+import de.kuschku.quasseldroid_ng.ui.chat.AutoCompleteAdapter
 import de.kuschku.quasseldroid_ng.ui.chat.NickListAdapter
 import de.kuschku.quasseldroid_ng.ui.chat.ToolbarFragment
 import de.kuschku.quasseldroid_ng.ui.chat.buffers.BufferListAdapter
@@ -192,6 +193,119 @@ class QuasselViewModel : ViewModel() {
     }
   }
 
+  val lastWord = MutableLiveData<Observable<String>>()
+
+  val autoCompleteData: LiveData<List<AutoCompleteAdapter.AutoCompleteItem>?> = session.zip(
+    buffer, lastWord
+  ).switchMapRx { (session, id, lastWordWrapper) ->
+    lastWordWrapper
+      .distinctUntilChanged()
+      .debounce(300, TimeUnit.MILLISECONDS)
+      .switchMap { lastWord ->
+        val bufferSyncer = session?.bufferSyncer
+        val bufferInfo = bufferSyncer?.bufferInfo(id)
+        if (bufferSyncer != null && lastWord.length >= 3) {
+          bufferSyncer.liveBufferInfos().switchMap { infos ->
+            if (bufferInfo?.type?.hasFlag(
+                Buffer_Type.ChannelBuffer
+              ) == true) {
+              val network = session.networks[bufferInfo.networkId]
+              val ircChannel = network?.ircChannel(
+                bufferInfo.bufferName
+              )
+              if (ircChannel != null) {
+                ircChannel.liveIrcUsers().switchMap { users ->
+                  val buffers: List<Observable<AutoCompleteAdapter.AutoCompleteItem.ChannelItem>?> = infos.values
+                    .filter {
+                      it.type.toInt() == Buffer_Type.ChannelBuffer.toInt()
+                    }.mapNotNull { info ->
+                      session.networks[info.networkId]?.let { info to it }
+                    }.map<Pair<BufferInfo, Network>, Observable<AutoCompleteAdapter.AutoCompleteItem.ChannelItem>?> { (info, network) ->
+                      network.liveIrcChannel(
+                        info.bufferName
+                      ).switchMap { channel ->
+                        channel.liveTopic().map { topic ->
+                          AutoCompleteAdapter.AutoCompleteItem.ChannelItem(
+                            info = info,
+                            network = network.networkInfo(),
+                            bufferStatus = when (channel) {
+                              IrcChannel.NULL -> BufferListAdapter.BufferStatus.OFFLINE
+                              else            -> BufferListAdapter.BufferStatus.ONLINE
+                            },
+                            description = topic
+                          )
+                        }
+                      }
+                    }
+                  val nicks = users.map<IrcUser, Observable<AutoCompleteAdapter.AutoCompleteItem.UserItem>?> { user ->
+                    user.liveNick().switchMap { nick ->
+                      user.liveRealName().switchMap { realName ->
+                        user.liveIsAway().map { away ->
+                          val userModes = ircChannel.userModes(
+                            user
+                          )
+                          val prefixModes = network.prefixModes()
+
+                          val lowestMode = userModes.mapNotNull {
+                            prefixModes.indexOf(
+                              it
+                            )
+                          }.min() ?: prefixModes.size
+
+                          AutoCompleteAdapter.AutoCompleteItem.UserItem(
+                            nick,
+                            network.modesToPrefixes(
+                              userModes
+                            ),
+                            lowestMode,
+                            realName,
+                            away,
+                            network.support(
+                              "CASEMAPPING"
+                            )
+                          )
+                        }
+                      }
+                    }
+                  }
+
+                  Observable.combineLatest(
+                    nicks + buffers,
+                    object :
+                      Function<Array<Any>, List<AutoCompleteAdapter.AutoCompleteItem>> {
+                      override fun apply(
+                        objects: Array<Any>): List<AutoCompleteAdapter.AutoCompleteItem> {
+                        return objects.toList() as List<AutoCompleteAdapter.AutoCompleteItem>
+                      }
+                    }).map { list ->
+                    list
+                      .filter {
+                        it.name.contains(
+                          lastWord,
+                          ignoreCase = true
+                        )
+                      }.sorted()
+                  }
+                }
+              } else {
+                Observable.just(
+                  emptyList()
+                )
+              }
+            } else {
+              Observable.just(
+                emptyList()
+              )
+            }
+          }
+        } else {
+          Observable.just(
+            emptyList()
+          )
+        }
+      }
+  }
+
   val bufferViewConfigs = bufferViewManager.switchMapRx { manager ->
     manager.liveBufferViewConfigs().map { ids ->
       ids.mapNotNull { id ->