/**
* Copyright (c) 2009, 2010 Mark Feber, MulgaSoft
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.mulgasoft.emacsplus.minibuffer;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Pattern;
import com.mulgasoft.emacsplus.EmacsPlusUtils;
import com.mulgasoft.emacsplus.RingBuffer;
import com.mulgasoft.emacsplus.commands.KbdMacroFileHandler;
import com.mulgasoft.emacsplus.execute.KbdMacroSupport;
import com.mulgasoft.emacsplus.execute.SelectionDialog;
/**
* @author Mark Feber - initial API and implementation
*
*/
public class KbdMacroMinibuffer extends CompletionMinibuffer {
KbdMacroFileHandler filehandler = null;
/**
* @param executable
*/
public KbdMacroMinibuffer(IMinibufferExecutable executable) {
super(executable);
if (executable instanceof KbdMacroFileHandler) {
filehandler = (KbdMacroFileHandler)executable;
}
}
/**
* @see com.mulgasoft.emacsplus.minibuffer.ExecutingMinibuffer#getMinibufferPrefix()
*/
protected String getMinibufferPrefix() {
return getCompletionMinibufferPrefix();
}
/**
* @see com.mulgasoft.emacsplus.execute.ISelectExecute#execute(java.lang.Object)
*/
public void execute(Object selection) {
String key = (String)selection;
setExecuting(true);
executeResult(getEditor(),key);
leave(true);
}
protected void showCompletions() {
String name = getMBString();
SortedMap<String, ?> viewTree;
if (isSearching() && getSearchStr().length() > 0) {
viewTree = getSearchResults();
} else {
viewTree = getCompletions(name);
}
if (viewTree != null) {
if (viewTree.size() > 1) {
if (getMiniDialog() == null) {
setMiniDialog(new SelectionDialog(null, this, getEditor()));
}
((SelectionDialog) getMiniDialog()).open(viewTree);
setShowingCompletions(true);
}
EmacsPlusUtils.forceStatusUpdate(getEditor());
String newName;
if (viewTree.size() == 0) {
updateStatusLine((isSearching() ? EMPTY_STR : name) + NOMATCH_MSG);
} else if (viewTree.size() == 1) {
closeDialog();
newName = viewTree.firstKey();
if (!name.equals(newName) && !isSearching()) {
initMinibuffer(newName);
}
updateStatusLine(newName + COMPLETE_MSG);
} else if (!isSearching()) {
if (name.length() > 0) {
newName = getCommonString(viewTree.keySet(),name);
if (!name.equals(newName)) {
initMinibuffer(newName);
}
}
updateStatusLine(getMBString());
}
} else {
updateStatusLine(name + NOMATCH_MSG);
}
}
protected SortedMap<String, ?> getCompletions(String searchSubstr, boolean insensitive, boolean regex) {
SortedMap<String, ?> result = getCompletions();
if (searchSubstr != null && result != null) {
Set<String> keySet = result.keySet();
String searchStr = (regex ? searchSubstr : toRegex(searchSubstr));
boolean isRegex = (regex || isRegex(searchStr,searchSubstr));
if (insensitive || isRegex) {
try {
SortedMap<String,? super Object> regResult = new TreeMap<String, Object>();
Pattern pat = Pattern.compile(searchStr + RWILD, (insensitive ? Pattern.CASE_INSENSITIVE : 0)); //$NON-NLS-1$
// we have to build the map up one by one on regex search
for (String key : keySet) {
if (pat.matcher(key).matches()) {
regResult.put(key, result.get(key));
}
}
result = regResult;
} catch (Exception e) {
// ignore any PatternSyntaxException
}
if (result.size() == 0 && !insensitive) {
// try non-regex lookup
result = getCompletions(searchSubstr, keySet);
}
} else {
result = getCompletions(searchSubstr, keySet);
}
if ((result == null || result.size() == 0) && !insensitive) {
// try once with case insensitivity
return getCompletions(searchSubstr, true, regex);
}
}
return result;
}
/**
* Walk the buffer list looking for matches with subString on initial characters
*
* @param subString
* @param result
* @param keySet
* @return subsection of map, each of whose entries start with subString
*/
private SortedMap<String, ?> getCompletions(String subString, Set<String> keySet) {
SortedMap<String, ?> result = null;
String fromKey = null;
String toKey = null;
for (String key : keySet) {
if (key.startsWith(subString)) {
if (fromKey == null) {
fromKey = key;
}
} else if (fromKey != null) {
toKey = key;
break;
}
}
// too bad we can't use 1.6
if (fromKey != null) {
if (toKey == null) {
result = getCompletions().tailMap(fromKey);
} else {
result = getCompletions().subMap(fromKey, toKey);
}
}
return result;
}
protected SortedMap<String, ?> getCompletions() {
if (filehandler != null) {
return filehandler.getCompletions();
} else {
return KbdMacroSupport.getCompletionList();
}
}
/**
* @see com.mulgasoft.emacsplus.minibuffer.WithMinibuffer#handlesTab()
*/
@Override
protected boolean handlesTab() {
// enable tab completion
return true;
}
/**
* @see com.mulgasoft.emacsplus.minibuffer.WithMinibuffer#handlesCtrl()
*/
@Override
protected boolean handlesAlt() {
// no history either
return false;
}
/**
* @see com.mulgasoft.emacsplus.minibuffer.HistoryMinibuffer#getHistoryRing()
*/
@Override
protected RingBuffer<Object> getHistoryRing() {
// No history on kbd macro names
return null;
}
}