mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-25 17:00:36 -09:00
Implement and document menu item mnemonic escaping
This commit is contained in:
@@ -128,9 +128,16 @@
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The tag indicates the top-level menu path. Path levels are delimited using the "."
|
||||
character.</P>
|
||||
character. A mnemonic can be defined by adding an ampersand ("&") in front of the mnemonic
|
||||
key. Ampersands can be escaped by adding another ampersand ("&&"). </P>
|
||||
|
||||
<P>For example, <TT>"@menupath File.Run.My Script"</TT>.</P>
|
||||
<P>For example:</P>
|
||||
<BLOCKQUOTE>
|
||||
<P><TT>@menupath File.Run.My Script<BR>
|
||||
@menupath File.Run.My &Script<BR>
|
||||
@menupath File.Run.Me && My &Script<BR>
|
||||
</TT></P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><CODE><B>@toolbar</B></CODE></P>
|
||||
|
||||
@@ -117,7 +117,7 @@ public class MenuData {
|
||||
|
||||
/**
|
||||
* Returns the menu path as a string. This method filters accelerator chars('&') from the path.
|
||||
* @return the menu path as a string without '&' chars
|
||||
* @return the menu path as a string without unescaped '&' chars
|
||||
*/
|
||||
public String getMenuPathDisplayString() {
|
||||
if (menuPath == null || menuPath.length == 0) {
|
||||
@@ -260,7 +260,7 @@ public class MenuData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the menu item name and the mnemonic, using the first '&' found in the text
|
||||
* Sets the menu item name and the mnemonic, using the first unescaped '&' found in the text
|
||||
* as a marker ("S&ave As").
|
||||
* <p>
|
||||
* NOTE: do NOT use this method with strings that contain user-supplied text. Instead, use
|
||||
@@ -305,7 +305,12 @@ public class MenuData {
|
||||
}
|
||||
|
||||
private static int getMnemonic(String string) {
|
||||
int indexOf = string.indexOf('&');
|
||||
int indexOf;
|
||||
int fromIndex = 0;
|
||||
do {
|
||||
indexOf = string.indexOf('&', fromIndex);
|
||||
fromIndex = indexOf + 2;
|
||||
} while (indexOf >= 0 && indexOf < string.length() - 1 && string.charAt(indexOf + 1) == '&');
|
||||
if (indexOf >= 0 && indexOf < string.length() - 1) {
|
||||
return string.charAt(indexOf + 1);
|
||||
}
|
||||
@@ -321,7 +326,18 @@ public class MenuData {
|
||||
}
|
||||
|
||||
private static String processMenuItemName(String string) {
|
||||
return string.replaceFirst("&", "");
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
if (string.charAt(i) == '&') {
|
||||
if (i < string.length() - 1 && string.charAt(i+1) == '&') {
|
||||
builder.append('&');
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
builder.append(string.charAt(i));
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public String getMenuItemName() {
|
||||
|
||||
@@ -34,6 +34,45 @@ public class MenuDataTest {
|
||||
MenuData menuData = new MenuData(new String[] { "One", "Two", "&Three" });
|
||||
assertEquals(menuData.getMnemonic(), 'T');
|
||||
}
|
||||
|
||||
/**
|
||||
* There should be no mnemonic, the ampersand is escaped.
|
||||
*/
|
||||
@Test
|
||||
public void testMenuDataMnemonicSkipsEscapedAmpersand() {
|
||||
MenuData menuData = new MenuData(new String[] { "One", "Two", "&&Three" });
|
||||
assertEquals(menuData.getMnemonic(), MenuData.NO_MNEMONIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* The mnemonic should be 'h'. The first two ampersands form an escaped
|
||||
* ampersand. The third ampersand is not escaped.
|
||||
*/
|
||||
@Test
|
||||
public void testMenuDataMnemonicEscapesAmpersandLeftToRight() {
|
||||
MenuData menuData = new MenuData(new String[] { "One", "Two", "T&&&hree" });
|
||||
assertEquals(menuData.getMnemonic(), 'h');
|
||||
}
|
||||
|
||||
/**
|
||||
* There should be no mnemonic, the trailing ampersand is not followed by any
|
||||
* character.
|
||||
*/
|
||||
@Test
|
||||
public void testMenuDataMnemonicIgnoresTrailingAmpersand() {
|
||||
MenuData menuData = new MenuData(new String[] { "One", "Two", "Three&" });
|
||||
assertEquals(menuData.getMnemonic(), MenuData.NO_MNEMONIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* The mnemonic should be 'T'. This is the expected behaviour as per the
|
||||
* "Desktop development with C++" workload in Visual Studio.
|
||||
*/
|
||||
@Test
|
||||
public void testMenuDataMnemonicParsesLeftToRight() {
|
||||
MenuData menuData = new MenuData(new String[] { "One", "Two", "&T&hree" });
|
||||
assertEquals(menuData.getMnemonic(), 'T');
|
||||
}
|
||||
|
||||
/**
|
||||
* Mnemonic should be 'h' based on the value that was explicitly set
|
||||
@@ -86,4 +125,23 @@ public class MenuDataTest {
|
||||
menuData.setMenuPath(newPath);
|
||||
assertEquals(menuData.getMnemonic(), MenuData.NO_MNEMONIC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMenuItemNameEscapesAmpersand() {
|
||||
MenuData menuData = new MenuData(new String[] { "One", "Two", "&&Three" });
|
||||
assertEquals(menuData.getMenuItemName(), "&Three");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ampersands that are not escaped should be ignored regardless of use as
|
||||
* mnemonics.
|
||||
*/
|
||||
@Test
|
||||
public void testGetMenuItemNameIgnoresUnescapedAmpersand() {
|
||||
MenuData menuData = new MenuData(new String[] { "One", "Two", "Three&" });
|
||||
assertEquals(menuData.getMenuItemName(), "Three");
|
||||
|
||||
menuData.setMenuItemName("&T&hree");
|
||||
assertEquals(menuData.getMenuItemName(), "Three");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user