Users can express creativity with web-based tools
Users can contribute to improve web-based tools
Feature reqests are directly bound to the code
Direct | Indirect | |
---|---|---|
Real-time | Collabode, Codeshare | - |
Async. | GitHub, UserVoice, BugHerd | HelpMeOut, Eclipse Code Recommenders, User-Generated Variables |
Programming language-oriented collaborations
The IDE should support Live Tuning or a similar architecture that allows to share the codebase between programmers and users.
Tracking is enabled by extending GUI Toolkits
// To support UGV, each GUI container should know
// where its constructor is called
interface CodeLocation {
filePath: string;
row: number;
column: number;
}
// GUI container is a parent of any kinds of widgets
class UGVContainer extends Container {
private loc: CodeLocation;
constructor() {
super();
this.loc = IDE.app.getCurrentContext().getCodeLocation();
// let the 'Propose' button know the code location
this.addProposeButton(container, loc);
}
// details omitted
}
Static code analysis with heuristics gives the answer
interface ParsedFile {
filePath: string;
ast: ASTNode;
}
class ProposeButton {
// details omitted
private loc: CodeLocation
onClick(proposal: Proposal) {
var file: ParsedFile = IDE.getParsedSourceFile(this.loc.filePath)
, ast = file.ast;
// In TextAlive, this file represents a single template class
// that defines a particular kind of visual effect.
var node: ASTNode = this.findLastFieldDeclaration(ast);
if (node) node = node.next();
else node = this.findFirstLineOfFunctionBody(ast);
IDE.addWidgetCode(proposal, node);
IDE.updateSourceFile(file);
}
}
Example app code with multiple field declarations
function RotateAndZoomWithBackground() {
this.name = "回って拡大/背景付き (RotateAndZoomWithBackground)";
this.type = PHRASE;
var da = require("DefaultAlignment");
var defaultAlignment = null;
// @ui Slider(0, 100)
// @title Rotation speed
// @title @ja 回転スピード
this.rotSpeed = 20;
// @ui Slider(1, 1000)
// @title Start time correction
// @title @ja 開始時刻補正
this.headTime = 300;
// @ui Slider(1, 1000)
// @title End time correction
// @title @ja 終了時刻補正
this.tailTime = 500;
// @ui Slider(-200, 200)
// @title Horizontal position
// @title @ja 横位置補正
this.x = 0;
// @ui Color()
// @title Background color
// @title @ja 背景色
this.primaryColor = new Color('#186f7f');
// @ui Color()
// @title Text color
// @title @ja 文字色
this.textColor = new Color('#ffffff');
// @ui Slider(-100, 100)
// @title Vertical position
// @title @ja 背景縦位置
this.yFix = 15;
Code snippet will be inserted here.
this.animate = function(now) {
// details omitted
};
}
Example app code with no field declaration
function TemplateWithNoCustomizationParameter() {
Code snippet will be inserted here.
this.animate = function(now) {
// details omitted
}
}
Application code is updated automatically & safely
interface Proposal {
type: string;
label: string;
options: object;
}
class IDE {
// details omitted
addWidgetCode(proposal: Proposal, node: ASTNode) {
var widgetCode = this.getWidgetCode(proposal, node);
file.ast.find(loc).insert(IDE.parse(widgetCode));
IDE.writeFile(file);
}
getWidgetCode(proposal: Proposal, node: ASTNode) {
var varName = this.findUniqueVariableName(node);
, code;
code = '// @proposed' + lineBreak;
code += '// @title ' + proposal.label + lineBreak;
code += '// ' + this.getWidgetConstructorCode(proposal) + lineBreak;
code += 'this.' + varName + ' = ' + JSON.stringify(proposal.options.defaultValue);
return code;
}
getWidgetConstructorCode(proposal: Proposal) {
var opt = proposal.options;
switch (proposal.type) {
case 'slider':
return '@ui Slider(' + opt.min + ', ' + opt.max + ')';
case 'check':
return '@ui Check()';
case 'color':
return '@ui Color()';
default:
return '@comment ' + opt.toString();
}
}
}
Example of inserted code snippet
// @proposed
// @title Font size
// @ui Slider(1, 1000)
this.var23495 = 500.5;
The current instances of the app need to refresh UIs
class IDE {
// details omitted
updateSourceFile(file: File) {
this.save(file);
this.updateView(file);
}
updateView(file: File) {
var container = this.app.getCorrespondingContainer(file);
container.reload();
}
}
3 rejections were made because ...
Mechanisms for consensus building are needed
Ease of use and flexibility should be balanced well
Widgets for more complex features are desired
Giving users write access to code seems like a terrible idea, especially at scale, but the very premise raises other interesting opportunities about embedding all kinds of user feedback in source.
Attracting attention to code could be the first step