diff --git a/src/add-ons/translators/jpeg/JPEGTranslator.cpp b/src/add-ons/translators/jpeg/JPEGTranslator.cpp index c6bb97b963..ab57fcb88e 100644 --- a/src/add-ons/translators/jpeg/JPEGTranslator.cpp +++ b/src/add-ons/translators/jpeg/JPEGTranslator.cpp @@ -402,7 +402,7 @@ SSlider::SSlider(const char* name, const char* label, const char* SSlider::UpdateText() const { - snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value()); + snprintf(fStatusLabel, sizeof(fStatusLabel), "%" B_PRId32, Value()); return fStatusLabel; } diff --git a/src/apps/debugger/controllers/ThreadHandler.cpp b/src/apps/debugger/controllers/ThreadHandler.cpp index 72e519b70b..5b79d148a5 100644 --- a/src/apps/debugger/controllers/ThreadHandler.cpp +++ b/src/apps/debugger/controllers/ThreadHandler.cpp @@ -269,6 +269,7 @@ ThreadHandler::HandleThreadAction(uint32 action) TRACE_CONTROL(" ip: %#" B_PRIx64 "\n", frame->InstructionPointer()); + target_addr_t frameIP = frame->GetCpuState()->InstructionPointer(); // When the thread is in a syscall, do the same for all step kinds: Stop it // when it returns by means of a breakpoint. if (frame->Type() == STACK_FRAME_TYPE_SYSCALL) { @@ -284,15 +285,14 @@ ThreadHandler::HandleThreadAction(uint32 action) // The second issue is that the temporary breakpoint is probably not necessary // anymore, since single-stepping over "syscall" instructions should just work // as expected. - status_t error = _InstallTemporaryBreakpoint( - frame->GetCpuState()->InstructionPointer()); + status_t error = _InstallTemporaryBreakpoint(frameIP); if (error != B_OK) { _StepFallback(); return; } fStepMode = STEP_OUT; - _RunThread(frame->GetCpuState()->InstructionPointer()); + _RunThread(frameIP); return; } @@ -303,9 +303,10 @@ ThreadHandler::HandleThreadAction(uint32 action) _StepFallback(); return; } + fPreviousInstructionPointer = frameIP; fPreviousFrameAddress = frame->FrameAddress(); fStepMode = STEP_OUT; - _RunThread(frame->GetCpuState()->InstructionPointer()); + _RunThread(frameIP); return; } @@ -324,7 +325,7 @@ ThreadHandler::HandleThreadAction(uint32 action) if (action == MSG_THREAD_STEP_INTO) { // step into fStepMode = STEP_INTO; - _SingleStepThread(frame->GetCpuState()->InstructionPointer()); + _SingleStepThread(frameIP); } else { fPreviousFrameAddress = frame->FrameAddress(); // step over @@ -648,7 +649,7 @@ ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState) " - step out adding return value\n", cpuState ->StackFramePointer(), fPreviousFrameAddress); ReturnValueInfo* info = new(std::nothrow) ReturnValueInfo( - cpuState->InstructionPointer(), cpuState); + fPreviousInstructionPointer, cpuState); if (info == NULL) return false; BReference infoReference(info, true); @@ -730,8 +731,8 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState) TRACE_CONTROL("ThreadHandler::_HandleSingleStepStep() " " - adding return value for STEP_OVER\n"); ReturnValueInfo* info = new(std::nothrow) - ReturnValueInfo(cpuState->InstructionPointer(), - cpuState); + ReturnValueInfo(fStepStatement + ->CoveringAddressRange().Start(), cpuState); if (info == NULL) return false; BReference infoReference(info, true); diff --git a/src/apps/terminal/HyperLink.cpp b/src/apps/terminal/HyperLink.cpp index 97e294f7eb..e3eab2843a 100644 --- a/src/apps/terminal/HyperLink.cpp +++ b/src/apps/terminal/HyperLink.cpp @@ -20,11 +20,19 @@ HyperLink::HyperLink() } -HyperLink::HyperLink(const BString& address, Type type, - const BString& baseAddress) +HyperLink::HyperLink(const BString& address, Type type) : + fText(address), + fAddress(address), + fType(type) +{ +} + + +HyperLink::HyperLink(const BString& text, const BString& address, Type type) + : + fText(text), fAddress(address), - fBaseAddress(baseAddress.IsEmpty() ? address : baseAddress), fType(type) { } diff --git a/src/apps/terminal/HyperLink.h b/src/apps/terminal/HyperLink.h index 735c84c50f..ba7d58a13e 100644 --- a/src/apps/terminal/HyperLink.h +++ b/src/apps/terminal/HyperLink.h @@ -20,20 +20,21 @@ public: public: HyperLink(); - HyperLink(const BString& address, Type type, - const BString& baseAddress = BString()); + HyperLink(const BString& address, Type type); + HyperLink(const BString& text, + const BString& address, Type type); bool IsValid() const { return !fAddress.IsEmpty(); } + const BString& Text() const { return fText; } const BString& Address() const { return fAddress; } - const BString& BaseAddress() const { return fBaseAddress; } Type GetType() const { return fType; } status_t Open(); private: + BString fText; BString fAddress; - BString fBaseAddress; Type fType; }; diff --git a/src/apps/terminal/TermViewStates.cpp b/src/apps/terminal/TermViewStates.cpp index 9591983adf..e0f33b24ee 100644 --- a/src/apps/terminal/TermViewStates.cpp +++ b/src/apps/terminal/TermViewStates.cpp @@ -30,6 +30,9 @@ #include #include +#include + +#include "ActiveProcessInfo.h" #include "Shell.h" #include "TermConst.h" #include "TerminalBuffer.h" @@ -52,6 +55,7 @@ static const uint32 kAutoScroll = 'AScr'; static const uint32 kMessageOpenLink = 'OLnk'; static const uint32 kMessageCopyLink = 'CLnk'; +static const uint32 kMessageCopyAbsolutePath = 'CAbs'; static const uint32 kMessageMenuClosed = 'MClo'; @@ -638,6 +642,7 @@ TermView::HyperLinkState::HyperLinkState(TermView* view) fURLCharClassifier(kURLAdditionalWordCharacters), fPathComponentCharClassifier( BString(kDefaultAdditionalWordCharacters).RemoveFirst("/")), + fCurrentDirectory(), fHighlight(), fHighlightActive(false) { @@ -648,6 +653,12 @@ TermView::HyperLinkState::HyperLinkState(TermView* view) void TermView::HyperLinkState::Entered() { + ActiveProcessInfo activeProcessInfo; + if (fView->GetActiveProcessInfo(activeProcessInfo)) + fCurrentDirectory = activeProcessInfo.CurrentDirectory(); + else + fCurrentDirectory.Truncate(0); + _UpdateHighlight(); } @@ -791,54 +802,108 @@ TermView::HyperLinkState::_GetHyperLinkAt(BPoint where, bool pathPrefixOnly, if (text.IsEmpty()) return false; - // check, whether the file exists - struct stat st; - if (lstat(text, &st) == 0) { - _link = HyperLink(text, HyperLink::TYPE_PATH); - return true; - } - - // As such this isn't an existing path. Try a few common alternative cases: - // * ":" - // * ":" - // * "::" - // * "::" - // * ":::" - - if (text.Length() <= 1) - return false; - - if (text[text.Length() - 1] == ':') { - text.Truncate(text.Length() - 1); - if (!textBuffer->PreviousLinePos(_end)) + // Collect a list of colons in the string and their respective positions in + // the text buffer. We do this up-front so we can unlock the text buffer + // while we're doing all the entry existence tests. + typedef Array ColonList; + ColonList colonPositions; + TermPos searchPos = _start; + for (int32 index = 0; (index = text.FindFirst(':', index)) >= 0;) { + TermPos foundStart; + TermPos foundEnd; + if (!textBuffer->Find(":", searchPos, true, true, false, foundStart, + foundEnd)) { return false; - - if (lstat(text, &st) == 0) { - _link = HyperLink(text, HyperLink::TYPE_PATH); - return true; } + + CharPosition colonPosition; + colonPosition.index = index; + colonPosition.position = foundStart; + if (!colonPositions.Add(colonPosition)) + return false; + + index++; + searchPos = foundEnd; } - BString path = text; + textBufferLocker.Unlock(); - for (int32 i = 0; i < 2; i++) { - int32 colonIndex = path.FindLast(':'); - if (colonIndex <= 0 || colonIndex == path.Length() - 1) - return false; + // Since we also want to consider ':' a potential path delimiter, in two + // nested loops we chop off components from the beginning respective the + // end. + BString originalText = text; + TermPos originalStart = _start; + TermPos originalEnd = _end; - char* numberEnd; - strtol(path.String() + colonIndex + 1, &numberEnd, 0); - if (*numberEnd != '\0') - return false; + int32 colonCount = colonPositions.Count(); + for (int32 startColonIndex = -1; startColonIndex < colonCount; + startColonIndex++) { + int32 startIndex; + if (startColonIndex < 0) { + startIndex = 0; + _start = originalStart; + } else { + startIndex = colonPositions[startColonIndex].index + 1; + _start = colonPositions[startColonIndex].position; + if (_start >= pos) + break; + _start.x++; + // Note: This is potentially a non-normalized position (i.e. + // the end of a soft-wrapped line). While not that nice, it + // works anyway. + } - path.Truncate(colonIndex); - if (lstat(path, &st) == 0) { - _link = HyperLink(text, - i == 0 - ? HyperLink::TYPE_PATH_WITH_LINE - : HyperLink::TYPE_PATH_WITH_LINE_AND_COLUMN, - path); - return true; + for (int32 endColonIndex = colonCount; endColonIndex > startColonIndex; + endColonIndex--) { + int32 endIndex; + if (endColonIndex == colonCount) { + endIndex = originalText.Length(); + _end = originalEnd; + } else { + endIndex = colonPositions[endColonIndex].index; + _end = colonPositions[endColonIndex].position; + if (_end <= pos) + break; + } + + originalText.CopyInto(text, startIndex, endIndex - startIndex); + if (text.IsEmpty()) + continue; + + // check, whether the file exists + BString actualPath; + if (_EntryExists(text, actualPath)) { + _link = HyperLink(text, actualPath, HyperLink::TYPE_PATH); + return true; + } + + // As such this isn't an existing path. We also want to recognize: + // * ":" + // * "::" + + BString path = text; + + for (int32 i = 0; i < 2; i++) { + int32 colonIndex = path.FindLast(':'); + if (colonIndex <= 0 || colonIndex == path.Length() - 1) + break; + + char* numberEnd; + strtol(path.String() + colonIndex + 1, &numberEnd, 0); + if (*numberEnd != '\0') + break; + + path.Truncate(colonIndex); + if (_EntryExists(path, actualPath)) { + BString address = path == actualPath + ? text : BString(fCurrentDirectory) << '/' << text; + _link = HyperLink(text, address, + i == 0 + ? HyperLink::TYPE_PATH_WITH_LINE + : HyperLink::TYPE_PATH_WITH_LINE_AND_COLUMN); + return true; + } + } } } @@ -846,6 +911,25 @@ TermView::HyperLinkState::_GetHyperLinkAt(BPoint where, bool pathPrefixOnly, } +bool +TermView::HyperLinkState::_EntryExists(const BString& path, + BString& _actualPath) const +{ + if (path.IsEmpty()) + return false; + + if (path[0] == '/' || fCurrentDirectory.IsEmpty()) { + _actualPath = path; + } else { + _actualPath.Truncate(0); + _actualPath << fCurrentDirectory << '/' << path; + } + + struct stat st; + return lstat(_actualPath, &st) == 0; +} + + void TermView::HyperLinkState::_UpdateHighlight() { @@ -948,9 +1032,12 @@ TermView::HyperLinkMenuState::Prepare(BPoint point, const HyperLink& link) case HyperLink::TYPE_PATH: case HyperLink::TYPE_PATH_WITH_LINE: case HyperLink::TYPE_PATH_WITH_LINE_AND_COLUMN: - menuBuilder - .AddItem(B_TRANSLATE("Open path"), kMessageOpenLink) - .AddItem(B_TRANSLATE("Copy path"), kMessageCopyLink); + menuBuilder.AddItem(B_TRANSLATE("Open path"), kMessageOpenLink); + menuBuilder.AddItem(B_TRANSLATE("Copy path"), kMessageCopyLink); + if (fLink.Text() != fLink.Address()) { + menuBuilder.AddItem(B_TRANSLATE("Copy absolute path"), + kMessageCopyAbsolutePath); + } break; } menu->SetTargetForItems(fView); @@ -975,22 +1062,27 @@ TermView::HyperLinkMenuState::MessageReceived(BMessage* message) return true; case kMessageCopyLink: + case kMessageCopyAbsolutePath: + { if (fLink.IsValid()) { + BString toCopy = message->what == kMessageCopyLink + ? fLink.Text() : fLink.Address(); + if (!be_clipboard->Lock()) return true; be_clipboard->Clear(); if (BMessage *data = be_clipboard->Data()) { - data->AddData("text/plain", B_MIME_TYPE, - fLink.Address().String(), - fLink.Address().Length()); + data->AddData("text/plain", B_MIME_TYPE, toCopy.String(), + toCopy.Length()); be_clipboard->Commit(); } be_clipboard->Unlock(); } return true; + } case kMessageMenuClosed: fView->_NextState(fView->fDefaultState); diff --git a/src/apps/terminal/TermViewStates.h b/src/apps/terminal/TermViewStates.h index af8e2955a8..106f2af195 100644 --- a/src/apps/terminal/TermViewStates.h +++ b/src/apps/terminal/TermViewStates.h @@ -128,10 +128,18 @@ private: virtual rgb_color BackgroundColor(); virtual uint32 AdjustTextAttributes(uint32 attributes); +private: + struct CharPosition { + int32 index; + TermPos position; + }; + private: bool _GetHyperLinkAt(BPoint where, bool pathPrefixOnly, HyperLink& _link, TermPos& _start, TermPos& _end); + bool _EntryExists(const BString& path, + BString& _actualPath) const; void _UpdateHighlight(); void _UpdateHighlight(BPoint where, int32 modifiers); @@ -142,6 +150,7 @@ private: private: DefaultCharClassifier fURLCharClassifier; DefaultCharClassifier fPathComponentCharClassifier; + BString fCurrentDirectory; TermViewHighlight fHighlight; bool fHighlightActive; }; diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index f9e8d4553c..808ac9272a 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -2704,6 +2704,7 @@ Desktop::WindowForClientLooperPort(port_id port) WindowList& Desktop::_Windows(int32 index) { + ASSERT(index >= 0 && index < kMaxWorkspaces); return fWorkspaces[index].Windows(); } diff --git a/src/tests/servers/app/playground/ObjectWindow.cpp b/src/tests/servers/app/playground/ObjectWindow.cpp index 0b6b9cc590..e78462287a 100644 --- a/src/tests/servers/app/playground/ObjectWindow.cpp +++ b/src/tests/servers/app/playground/ObjectWindow.cpp @@ -92,8 +92,9 @@ class ObjectListView : public BListView { virtual bool InitiateDrag(BPoint point, int32 itemIndex, bool wasSelected) { - printf("InitiateDrag(BPoint(%.1f, %.1f), itemIndex: %ld, wasSelected: %d)\n", - point.x, point.y, itemIndex, wasSelected); + printf("InitiateDrag(BPoint(%.1f, %.1f), itemIndex: %" B_PRId32 + ", wasSelected: %d)\n", point.x, point.y, itemIndex, + wasSelected); SwapItems(itemIndex, itemIndex + 1); return true; }