Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make parameter injection work with Azure Copilot response #244

Merged
merged 4 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions shell/AIShell.Abstraction/IShell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ public interface IShell
/// </summary>
CancellationToken CancellationToken { get; }

/// <summary>
/// Extracts code blocks that are surrounded by code fences from the passed-in markdown text.
/// </summary>
/// <param name="text">The markdown text.</param>
/// <returns>A list of code blocks or null if there is no code block.</returns>
List<CodeBlock> ExtractCodeBlocks(string text, out List<SourceInfo> sourceInfos);

// TODO:
// - methods to run code: python, command-line, powershell, node-js.
// - methods to communicate with shell client.
Expand Down
11 changes: 11 additions & 0 deletions shell/AIShell.Abstraction/IStreamRender.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
namespace AIShell.Abstraction;

/// <summary>
/// Represents a code block from a markdown text.
/// </summary>
public record CodeBlock(string Code, string Language);

/// <summary>
/// Represents the source metadata information of a code block extracted from a given markdown text.
/// </summary>
/// <param name="Start">The start index of the code block within the text.</param>
/// <param name="End">The end index of the code block within the text.</param>
/// <param name="Indents">Number of spaces for indentation used by the code block.</param>
public record SourceInfo(int Start, int End, int Indents);

public interface IStreamRender : IDisposable
{
string AccumulatedContent { get; }
Expand Down
2 changes: 1 addition & 1 deletion shell/AIShell.Kernel/Render/StreamRender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal DummyStreamRender(CancellationToken token)

public string AccumulatedContent => _buffer.ToString();

public List<CodeBlock> CodeBlocks => Utils.ExtractCodeBlocks(_buffer.ToString());
public List<CodeBlock> CodeBlocks => Utils.ExtractCodeBlocks(_buffer.ToString(), out _);

public void Refresh(string newChunk)
{
Expand Down
1 change: 1 addition & 0 deletions shell/AIShell.Kernel/Shell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ internal sealed class Shell : IShell

IHost IShell.Host => Host;
CancellationToken IShell.CancellationToken => _cancellationSource.Token;
List<CodeBlock> IShell.ExtractCodeBlocks(string text, out List<SourceInfo> sourceInfos) => Utils.ExtractCodeBlocks(text, out sourceInfos);

#endregion IShell implementation

Expand Down
97 changes: 71 additions & 26 deletions shell/AIShell.Kernel/Utility/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,21 +125,63 @@ internal static bool Contains(string left, string right)
}

/// <summary>
/// Extract code blocks from the passed-in text.
/// Extracts code blocks that are surrounded by code fences from the passed-in markdown text.
/// </summary>
internal static List<CodeBlock> ExtractCodeBlocks(string text)
internal static List<CodeBlock> ExtractCodeBlocks(string text, out List<SourceInfo> sourceInfos)
{
sourceInfos = null;

if (string.IsNullOrEmpty(text))
{
return null;
}

int start, index = -1;
int codeBlockStart = -1, codeBlockIndents = -1;
bool inCodeBlock = false;
string language = null;
string language = null, codeFenceInUse = null;
StringBuilder code = null;
List<CodeBlock> codeBlocks = null;

bool CodeFenceStarts(ReadOnlySpan<char> curLine)
{
const string BacktickFence = "```";
const string TildeFence = "~~~";

if (inCodeBlock || curLine.IsEmpty)
{
return false;
}

if (curLine.StartsWith(BacktickFence))
{
inCodeBlock = true;
codeFenceInUse = BacktickFence;
return true;
}

if (curLine.StartsWith(TildeFence))
{
inCodeBlock = true;
codeFenceInUse = TildeFence;
return true;
}

return false;
}

bool CodeFenceEnds(ReadOnlySpan<char> curLine)
{
if (inCodeBlock && curLine.SequenceEqual(codeFenceInUse))
{
inCodeBlock = false;
codeFenceInUse = null;
return true;
}

return false;
}

do
{
start = index + 1;
Expand All @@ -156,33 +198,35 @@ internal static List<CodeBlock> ExtractCodeBlocks(string text)

// Trim the line before checking for code fence.
ReadOnlySpan<char> lineTrimmed = line.Trim();
if (lineTrimmed.StartsWith("```"))

if (CodeFenceStarts(lineTrimmed))
{
if (inCodeBlock)
{
if (lineTrimmed.Length is 3)
{
// Current line is the ending code fence.
codeBlocks.Add(new CodeBlock(code.ToString(), language));

code.Clear();
language = null;
inCodeBlock = false;
continue;
}

// It's not the ending code fence, so keep appending to code.
code.Append(line);
}
else
// Current line is the starting code fence.
code ??= new StringBuilder();
codeBlocks ??= [];
sourceInfos ??= [];

language = lineTrimmed.Length > 3 ? lineTrimmed[3..].ToString() : null;
// No need to capture the code block start index if we already reached end of the text.
codeBlockStart = index is -1 ? -1 : index + 1;
codeBlockIndents = line.IndexOf(codeFenceInUse);

continue;
}

if (CodeFenceEnds(lineTrimmed))
{
// Current line is the ending code fence.
if (code.Length > 0)
{
// Current line is the starting code fence.
code ??= new StringBuilder();
codeBlocks ??= [];
inCodeBlock = true;
language = lineTrimmed.Length > 3 ? lineTrimmed[3..].ToString() : null;
codeBlocks.Add(new CodeBlock(code.ToString(), language));
sourceInfos.Add(new SourceInfo(codeBlockStart, start - 1, codeBlockIndents));
}

code.Clear();
language = null;
codeBlockStart = codeBlockIndents = -1;

continue;
}

Expand All @@ -198,6 +242,7 @@ internal static List<CodeBlock> ExtractCodeBlocks(string text)
{
// It's possbile that the ending code fence is missing.
codeBlocks.Add(new CodeBlock(code.ToString(), language));
sourceInfos.Add(new SourceInfo(codeBlockStart, text.Length - 1, codeBlockIndents));
}

return codeBlocks;
Expand Down
3 changes: 2 additions & 1 deletion shell/Markdown.VT/ColorCode.VT/Parser/Bash.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ public bool HasAlias(string lang)
{
case "sh":
return true;

case "azurecli":
return true;
default:
return false;
}
Expand Down
Loading